From 4f71385126319e736e7e663088fb9cc6e2188ce2 Mon Sep 17 00:00:00 2001 From: Bryan Stansell Date: Mon, 22 Sep 2003 13:49:53 -0700 Subject: [PATCH] Imported from conserver-8.0.0.tar.gz --- CHANGES | 90 +- FAQ | 20 +- INSTALL | 53 +- README | 23 +- TODO | 56 +- compat.h | 44 +- config.guess | 273 +- config.h.in | 48 +- config.sub | 102 +- configure | 2555 ++++++++------- configure.in | 178 +- conserver.cf/INSTALL | 14 +- conserver.cf/Makefile.in | 4 + conserver.cf/conserver.cf | 60 +- conserver.cf/conserver.cf.man | 881 ++++-- conserver.cf/conserver.passwd | 6 +- conserver.cf/conserver.passwd.man | 109 +- conserver.cf/test.cf | 65 +- conserver.html | 12 +- conserver/Makefile.in | 10 +- conserver/access.c | 249 +- conserver/access.h | 14 +- conserver/client.c | 193 +- conserver/client.h | 42 +- conserver/consent.c | 1029 +++--- conserver/consent.h | 133 +- conserver/conserver.man | 353 ++- conserver/convert.c | 511 +++ conserver/fallback.c | 259 +- conserver/group.c | 4351 ++++++++++++++----------- conserver/group.h | 17 +- conserver/main.c | 954 ++++-- conserver/main.h | 16 +- conserver/master.c | 880 ++++-- conserver/readcfg.c | 4904 +++++++++++++++++++++++------ conserver/readcfg.h | 68 +- conserver/util.c | 1093 +++++-- conserver/util.h | 52 +- conserver/version.h | 4 +- console/Makefile.in | 2 +- console/console.c | 1246 +++----- console/console.man | 489 ++- console/getpassword.c | 159 + console/getpassword.h | 10 + contrib/maketestcerts | 6 +- contrib/redhat-rpm/conserver.spec | 2 +- contrib/solaris-package/pkginfo | 2 +- test/dotest | 21 +- test/results/test11 | 16 +- test/results/test12 | 9 +- test/results/test13 | 6 +- test/results/test14 | 4 - test/results/test3 | 11 +- test/results/test8 | 10 +- test/test.cf | 34 +- test/test1.cf | 34 +- test/test2.cf | 41 +- 57 files changed, 13963 insertions(+), 7864 deletions(-) create mode 100644 conserver/convert.c create mode 100644 console/getpassword.c create mode 100644 console/getpassword.h delete mode 100644 test/results/test14 diff --git a/CHANGES b/CHANGES index ec4ca94..7550c00 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,94 @@ CHANGES ======= +version 8.0.0 (Sep 22, 2003): + - better error messages and management of the user's password + - 8.0.0-beta4 mistakenly lost conserver.passwd usage + - empty passwords now don't trigger a passwd prompt (like 7.2.7) + - upgraded to autoconf-2.57 and use recent config.guess/sub + files - suggested by Jorgen Hagg + - we now install the conserver.rc file as well as sample + conserver.cf and conserver.passwd files in + $(prefix)/share/examples/conserver - suggested by + Hubert Feyrer + +version 8.0.0-beta4 (Aug 24, 2003): + - totally rewrote the client/server communication, allowing SSL + connections to occur first, protecting *all* information + - added 'admin' keyword to the 'access' portion of the config + file for specifying users able to issue the 'quit' command + - removed client -G option since it's not really useful any more + - added client -t option for sending "text messages" to users, + which is similar to broadcast messages, but you can specify + the user and/or console - suggested by Trevor Fiatal + + - added client -d option for disconnecting users specified by + username and/or console - suggested by Trevor Fiatal + + - removed --with-64bit configure option as 64bit operation is + reported to work just fine + - break strings with '\d' are interpreted as a delay, which can + be specified in the config file (default 250ms) + - removed 'reset -x' portion of default break sequence #3 + - remote conserver hostnames now properly match - had to be a + character string match previously + - hostname aliases now checked against access lists and the + matched name is used for logging + - added --with-trustrevdns to enable the use of reverse DNS + information for access list checks [not recommended] - see the + INSTALL file for full details on who should actually need this + Many thanks to Chuck Rouzer for all the + help with FreeBSD support and the following issues... + - fixed 'make test' problem on hosts where 'localhost' doesn't + resolve to 127.0.0.1 + - fixed interface probe problem under *BSD + - added openpty() interface for pty allocation + +version 8.0.0-beta3 (Aug 8, 2003): + - master process no longer forks on client requests - handles + them with select() like child process + - alarm()/SIGALRM usage removed and replaced with counters and + timer on select() call + - removed caching of timeouts to terminal servers - each + socket connection now has a proper timeout (and can happen + simultaniously) + - partial write()s are properly buffered and retried + - made all sockets (including SSL) non-buffered + - client now supports piping data to it and properly printing + all server data ("echo '^Ecr^Ec.' | console universe") + +version 8.0.0-beta2 (Jul 17, 2003): + - console aliases added with 'aliases' console keyword + - two stop bit support for serial devices - requested by Kelly + Setzer + - added support for inet_aton() over inet_addr() + - all server interfaces now used to identify console management + - server interfaces probed with SIOCGIFCONF ioctl, if available + - added flow control options 'ixon', 'ixany', 'ixoff', and + 'crtscts' + - added info to console client -i output + - man pages updated, however the wording needs work + +version 8.0.0-beta1 (Jul 4, 2003): + - ***NOTICE*** the format of conserver.cf and conserver.passwd + has completely changed. see the INSTALL file for + upgrade instructions (it should be "fairly painless"). + some documentation has been updated to reflect the new world, + some hasn't - my goal for beta2 is to have all the docs updated + - many command-line options now also conserver.cf options options + - POSIX termios interface now required for compilation - some + POSIX requirements were already in the code and others will + undoubtedly creep in as time goes by + - configure --with-regex option removed because of conserver.cf + and conserver.passwd changes + - added -S option to server for syntax checking of the + configuration file - suggested by Dave Stuit + - authorized users now either have r/w or r/o access to consoles + - getpassword.o replaces getpass() and getpassphrase() so we can + get any string length + - fixed rm commands in test script - patch by Petter Reinholdtsen + + version 7.2.7 (Apr 9, 2003): - added test suite ('make test') for basic client/server communication tests @@ -429,5 +517,5 @@ before version 6.05: and enhancements of various types were applied. # -# $Id: CHANGES,v 1.82 2003-04-09 07:20:21-07 bryan Exp $ +# $Id: CHANGES,v 1.103 2003-09-22 10:42:00-07 bryan Exp $ # diff --git a/FAQ b/FAQ index d2c8974..631acda 100644 --- a/FAQ +++ b/FAQ @@ -65,23 +65,25 @@ directed to faq@conserver.com. The FAQ answers the following questions: When conserver was compiled, it was told to use the /etc/services entry of "conserver" (what came after getservbyname:). You'll need to either recompile conserver and hard-code a port number (using - PORT instead of SERVICE in conserver/cons.h) or enter "conserver" - in /etc/services. + --with-port=) or enter "conserver" in /etc/services. 6) What does "console: gethostbyname: console: host lookup error" mean (or something close to that)? When the console command was compiled, it was told to use the hostname "console" (what came after gethostbyname:) as the master - conserver host. You'll need to either recompile console with the - appropriate name of your conserver host or add an alias of "console". - In most cases, adding an alias is my suggestion. + conserver host. You'll need to either reconfigure with the + appropriate name of your conserver host (--with-master=) or + add an alias of "console". In most cases, adding an alias is my + suggestion. 7) How do I set up a local serial port for no parity? - The conserver.cf man page will have this in the 6.17 release, - but the answer is to use a 'p' after the baud rate. So, '9600p' - is 9600 baud, no parity. + The manpage has the answer to this question. For those that don't + want to read it, here are some guidelines. For pre-7.2.2, you'd + want to use a 'p' after the baud rate ("9600p", for example). For + 7.2.2 thru 7.2.7, you can use an 'n'. For 8.0.0 and beyond, you use + 'parity none;'. 8) Is "Conserver" a trademark or registered trademark? @@ -184,5 +186,5 @@ directed to faq@conserver.com. The FAQ answers the following questions: through the same problem? # -# $Id: FAQ,v 1.8 2003-04-08 14:05:16-07 bryan Exp $ +# $Id: FAQ,v 1.9 2003-08-23 12:27:10-07 bryan Exp $ # diff --git a/INSTALL b/INSTALL index 27546e2..07f99e0 100644 --- a/INSTALL +++ b/INSTALL @@ -10,6 +10,54 @@ Upgrading? new features added to the client if you're considering *not* upgrading. + Version 8.0.0 + + - The client/server protocol has been rearchitected. You *MUST* + use an 8.0.0 client with an 8.0.0 server. No combination of + client/server will work with pre-8.0.0 code. + + - Upgrading from pre-8.0.0 code to 8.0.0 and beyond requires + you to change your conserver.cf and conserver.passwd files + because both of the file formats have changed. + + The conserver.cf file changes are so major that there is a + convert program available in the conserver subdirectory. Just + run './conserver/convert ' and it will attempt a + conversion to the new format, sending it to stdout. Any errors + will be printed to stderr. There are a couple of things + you might need to adjust. First are the user access lists. + If you are restricting users to certain consoles in your old + conserver.passwd file, you'll need to move those restrictions + into the new conserver.cf file. Restrictions are set with the + 'ro' and 'rw' tags in the configuration file. Second are the + 'access' blocks. What get produced by the convert program + will be functionally equivalent to the old behavior, but you + may be able to tune things to better suit your environment. + + The conserver.passwd file's console restrictions have moved, + as described above. So to convert the conserver.passwd file, + all you really need to do is something like: + + awk -F: '{print $1 ":" $2}' + + If you have comments or continuation lines in your file, + you'll have to do a bit more cleanup to strip out the third + field (which is what the awk command is intending to do). + + - Conserver no longer trusts reverse DNS information by default. + If you use the --with-trustrevdns configure flag, you can + re-enable the use of gethostbyaddr() [I don't recommended it, + however]. If you are using domain names in access lists, + you'll either need to change those to use hostnames and/or ip + addresses/ranges or use the --with-trustrevdns flag. For + example, if you have (in the + 8.0.0 format): + + allowed conserver.com; # allow *.conserver.com + + then you'll need to worry about this change. If you only use + full hostnames, you shouldn't have to do anything. + Version 7.2.4 - If SSL support is compiled into the code, older versions of @@ -70,7 +118,6 @@ Detailed Instructions the defaults shown, you're set. If not, here are the conserver unique options: - --with-64bit Allow 64bit compilation --with-port=PORT Specify port number [conserver] --with-base=PORT Base port for secondary channel [0] --with-master=MASTER Specify master server hostname [console] @@ -82,10 +129,10 @@ Detailed Instructions --with-pidfile=PIDFILE Specify PID filepath [/var/run/conserver.pid] --with-maxmemb=MAXMEMB Specify maximum consoles per process [16] --with-timeout=TIMEOUT Specify connect() timeout in seconds [10] + --with-trustrevdns Trust reverse DNS information --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support --with-openssl[=PATH] Compile in OpenSSL support --with-dmalloc[=PATH] Compile in dmalloc support - --with-regex Use regular expressions in conserver.passwd --with-pam Enable PAM support Not surprisingly, some match the old conserver/cons.h items...here @@ -192,5 +239,5 @@ Other Information And Gotchas # -# $Id: INSTALL,v 1.27 2003-04-09 07:15:27-07 bryan Exp $ +# $Id: INSTALL,v 1.32 2003-08-23 11:20:55-07 bryan Exp $ # diff --git a/README b/README index cb4610f..7b2cfa1 100644 --- a/README +++ b/README @@ -24,17 +24,22 @@ Systems Tested compile conserver. If anyone has more to add to this list (or something on the list doesn't work any more), please let me know. - Solaris 2.5.1 thru 9 (sparc/x86), gcc + AIX 4.3.3/5.1/5.2, native cc BSDI BSD/OS 3.X, gcc - MacOS X + Cygwin (w2k),gcc 2.95.3 + DEC Tru64 4.0, gcc + DEC Tru64 4.0/5.1, native cc + FreeBSD 4.2/4.8/5.1 (x86), gcc + HP-UX 10.20, gcc + HP-UX 11.10 parisc and ia64, native cc + Irix 6.15, native cc Linux 2.2.18 (x86), gcc Linux 2.4.2 (x86), gcc - FreeBSD 4.2 (x86), gcc - cygwin (w2k),gcc 2.95.3 - DEC Tru64 4.0, gcc - DEC Tru64 4.0/5.1, DEC cc - HP-UX 10.20, gcc - AIX 4.3.3, AIX cc + Linux ia64, native gcc + Linux RedHat 6.2 and 7.2 (x86), native gcc + MacOS X, native gcc + Solaris 2.5.1 thru 9 (sparc/x86), gcc + Solaris 7/8, native cc Contributions @@ -50,5 +55,5 @@ Contributions http://www.columbia.edu/acis/sy/unixdev/zinc # -# $Id: README,v 1.21 2002-09-23 10:10:11-07 bryan Exp $ +# $Id: README,v 1.22 2003-08-23 12:34:24-07 bryan Exp $ # diff --git a/TODO b/TODO index 662d721..f61c231 100644 --- a/TODO +++ b/TODO @@ -10,20 +10,6 @@ Bryan Stansell --------------------------------------------------------------------------- -- usleep() statements, can they be removed and mimiced with some sort - of console state thing and a timer? Aaron Burt - users email. - -- OpenSSL sockets have been make blocking instead of keeping the - underlying socket non-blocking. Why? It requires much more work to - deal with non-blocking sockets and OpenSSL. Not impossible, just have - to rewrite a lot of the code to handle the extra special cases. Perhaps - by ignoring renegotiations this can be ignored, but I'm not sure. - -- checks for EPIPE during write() should really be done, but, for the - most part, consoles and clients will come around and we'll see - problems on the read(). - - Singular logging so that swatch/logsurfer can watch for errors across the board - unloved output comes close @@ -40,37 +26,30 @@ Bryan Stansell in regards to --use-libwrap code - alternate (md5) password encryption support in conserver.passwd + - actually happens if the crypt() call supports it, like under linux + - hpux has bigcrypt() also, which we support, so maybe we're covered - config file examples for various configurations - per-line timestamps - only when not connected? -- flow control configuration (hardcoded on, i think) - - pipe input/output (console <-> program) via 'console' - some apps (net-ups thing, gdb) might need to talk to user -- group permissions (better user management in general) - -- 64-bit compilation support (have a patch set contributed, somewhere, i think) - - autologout? setting per console? gack, would have to interpret data. - "listen" capability (watch all/multiple consoles) -- break sequences - need .5 second delays (or delays in general?) - -- aliases for console entries +- send data to multiple consoles (carbon copy) - + Steve Lammert - authentication to terminal servers (ssh, passphrase, whatever) - -- "not" or "except" in passwd file (!console). - -- multi-homed/multi-ip hosts not supported well - - other names/ip addrs not detected as local, necessarily - - acls don't look at aliases properly - - the whole thing needs some serious help + - ssh should probably just be handled by invoking the ssh command. + so, that's really already covered, no? + - passphrase...hmmm..could really use some sort of send/expect + thing here. you could write a wrapper script of sorts, but it + really would be nice to have a raw socket and do the right thing. - cyclades ts1000/2000 port : "Moses, Joel" @@ -94,20 +73,6 @@ Bryan Stansell - suggestions by Trevor Fiatal - include server hostname on 'console -x' output - - non-interactively be able to - - disconnect a single user-to-port session - - disconnect all sessions to a given port - - disconnect all sessions registered to a particular user - - non-interactively be able to send messages to - - all sessions open by a particular user - console -t user "Time to go home." - - a particular user-session - console -t user@managed-host "Please disconnect from this host." - - all users on a given host - console -t @managed-host "I am taking over this host." - -- support 2 stop bits (as well as other stty-type options in console - definitions) : Kelly Setzer - ability to configure strings to be sent to a console whenever it is (re)opened (eg. a termserver login) : Greg A. Woods @@ -119,7 +84,6 @@ Bryan Stansell - show attach/detach events to/of spy console clients : Greg A. Woods - # -# $Id: TODO,v 1.27 2003-01-27 17:47:27-08 bryan Exp $ +# $Id: TODO,v 1.36 2003-08-24 15:11:03-07 bryan Exp $ # diff --git a/compat.h b/compat.h index 8c7f8b1..e30f34e 100644 --- a/compat.h +++ b/compat.h @@ -1,5 +1,18 @@ #include +/* things everything seems to need */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + /* If, when processing a logfile for replaying the last N lines, * we end up seeing more than MAXREPLAYLINELEN characters in a line, * abort processing and display the data. Why? There could be some @@ -76,17 +89,7 @@ typedef long fd_set; # include #endif -#ifdef HAVE_TERMIOS_H -# include /* POSIX */ -#else -# ifdef HAVE_TERMIO_H -# include /* SysV */ -# else -# ifdef HAVE_SGTTY_H -# include /* BSD */ -# endif -# endif -#endif +#include #ifdef HAVE_STROPTS_H # include @@ -211,6 +214,18 @@ extern char *h_errlist[]; #include #endif +#ifdef HAVE_PTY_H +#include +#endif + +#ifdef HAVE_LIBUTIL_H +#include +#endif + +#ifdef HAVE_UTIL_H +#include +#endif + #ifndef NGROUPS_MAX # define NGROUPS_MAX 8 @@ -277,7 +292,12 @@ typedef int socklen_t; # define PARAMS(protos) protos # else /* no PROTOTYPES */ # define PARAMS(protos) () -# endif /* no PROTOTYPES */ +# endif /* no PROTOTYPES */ +#endif + +/* setup a conditional debugging line */ +#ifndef CONDDEBUG +#define CONDDEBUG(line) if (fDebug) {debugFileName=__FILE__; debugLineNo=__LINE__; Debug line;} #endif #if HAVE_DMALLOC diff --git a/config.guess b/config.guess index f1657bb..d56c46d 100755 --- a/config.guess +++ b/config.guess @@ -1,9 +1,9 @@ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002 Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -timestamp='2002-09-03' +timestamp='2003-08-18' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -98,30 +98,32 @@ trap 'exit 1' 1 2 15 # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. -# This shell variable is my proudest work .. or something. --bje +# Portable tmp directory creation inspired by the Autoconf team. -set_cc_for_build='tmpdir=${TMPDIR-/tmp}/config-guess-$$ ; -(old=`umask` && umask 077 && mkdir $tmpdir && umask $old && unset old) - || (echo "$me: cannot create $tmpdir" >&2 && exit 1) ; -dummy=$tmpdir/dummy ; -files="$dummy.c $dummy.o $dummy.rel $dummy" ; -trap '"'"'rm -f $files; rmdir $tmpdir; exit 1'"'"' 1 2 15 ; +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do - if ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; then + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; - rm -f $files ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; -unset files' +esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) @@ -178,7 +180,18 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # The OS release - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. @@ -227,68 +240,52 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - eval $set_cc_for_build - cat <$dummy.s - .data -\$Lformat: - .byte 37,100,45,37,120,10,0 # "%d-%x\n" - - .text - .globl main - .align 4 - .ent main -main: - .frame \$30,16,\$26,0 - ldgp \$29,0(\$27) - .prologue 1 - .long 0x47e03d80 # implver \$0 - lda \$2,-1 - .long 0x47e20c21 # amask \$2,\$1 - lda \$16,\$Lformat - mov \$0,\$17 - not \$1,\$18 - jsr \$26,printf - ldgp \$29,0(\$26) - mov 0,\$16 - jsr \$26,exit - .end main -EOF - $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null - if test "$?" = 0 ; then - case `$dummy` in - 0-0) - UNAME_MACHINE="alpha" - ;; - 1-0) - UNAME_MACHINE="alphaev5" - ;; - 1-1) - UNAME_MACHINE="alphaev56" - ;; - 1-101) - UNAME_MACHINE="alphapca56" - ;; - 2-303) - UNAME_MACHINE="alphaev6" - ;; - 2-307) - UNAME_MACHINE="alphaev67" - ;; - 2-1307) - UNAME_MACHINE="alphaev68" - ;; - 3-1307) - UNAME_MACHINE="alphaev7" - ;; - esac - fi - rm -f $dummy.s $dummy && rmdir $tmpdir echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead @@ -327,6 +324,9 @@ EOF NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; @@ -437,10 +437,9 @@ EOF exit (-1); } EOF - $CC_FOR_BUILD $dummy.c -o $dummy \ + $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ - && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 - rm -f $dummy.c $dummy && rmdir $tmpdir + && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) @@ -449,7 +448,7 @@ EOF Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; - Night_Hawk:*:*:PowerMAX_OS) + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) @@ -524,8 +523,7 @@ EOF exit(0); } EOF - $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 - rm -f $dummy.c $dummy && rmdir $tmpdir + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 @@ -623,11 +621,21 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`$dummy` - if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi - rm -f $dummy.c $dummy && rmdir $tmpdir + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) @@ -661,8 +669,7 @@ EOF exit (0); } EOF - $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 - rm -f $dummy.c $dummy && rmdir $tmpdir + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) @@ -720,15 +727,15 @@ EOF CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; - CRAY*T3D:*:*:*) - echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` @@ -744,7 +751,7 @@ EOF *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; - *:FreeBSD:*:*) + *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c @@ -756,8 +763,10 @@ EOF #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` - rm -f $dummy.c && rmdir $tmpdir - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + # GNU/FreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin @@ -768,14 +777,17 @@ EOF i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; - x86:Interix*:3*) - echo i386-pc-interix3 + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? - echo i386-pc-interix + echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin @@ -795,6 +807,9 @@ EOF arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; @@ -818,8 +833,26 @@ EOF #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` - rm -f $dummy.c && rmdir $tmpdir - test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0 + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu @@ -855,6 +888,9 @@ EOF s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; @@ -912,9 +948,11 @@ EOF LIBC=gnuaout #endif #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` - rm -f $dummy.c && rmdir $tmpdir test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; @@ -932,6 +970,23 @@ EOF # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then @@ -966,9 +1021,6 @@ EOF echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; - i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about @@ -995,9 +1047,12 @@ EOF mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0) + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` @@ -1014,9 +1069,6 @@ EOF mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; @@ -1098,7 +1150,11 @@ EOF echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) - echo `uname -p`-apple-darwin${UNAME_RELEASE} + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` @@ -1134,11 +1190,6 @@ EOF fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; @@ -1157,11 +1208,8 @@ EOF *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; - i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit 0 ;; - i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; esac @@ -1283,8 +1331,7 @@ main () } EOF -$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 -rm -f $dummy.c $dummy && rmdir $tmpdir +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. diff --git a/config.h.in b/config.h.in index 65abecd..5932545 100644 --- a/config.h.in +++ b/config.h.in @@ -45,9 +45,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H -/* Define to 1 if you have the `getpassphrase' function. */ -#undef HAVE_GETPASSPHRASE - /* Define to 1 if you have the `getprpwnam' function. */ #undef HAVE_GETPRPWNAM @@ -72,6 +69,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_HPSECURITY_H +/* Define to 1 if you have the `inet_aton' function. */ +#undef HAVE_INET_ATON + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H @@ -87,6 +87,12 @@ /* Define to 1 if you have the `sec' library (-lsec). */ #undef HAVE_LIBSEC +/* Define to 1 if you have the `util' library (-lutil). */ +#undef HAVE_LIBUTIL + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBUTIL_H + /* Define to 1 if you have the `xnet' library (-lxnet). */ #undef HAVE_LIBXNET @@ -96,30 +102,39 @@ /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET +/* Define to 1 if you have the `openpty' function. */ +#undef HAVE_OPENPTY + /* have openssl support */ #undef HAVE_OPENSSL /* have PAM support */ #undef HAVE_PAM -/* have POSIX regcomp */ -#undef HAVE_POSIX_REGCOMP - /* Define to 1 if you have the header file. */ #undef HAVE_PROT_H /* Define to 1 if you have the `ptsname' function. */ #undef HAVE_PTSNAME +/* Define to 1 if you have the header file. */ +#undef HAVE_PTY_H + /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV +/* Defined if sa_len member exists in struct sockaddr */ +#undef HAVE_SA_LEN + /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS @@ -141,9 +156,6 @@ /* Define to 1 if you have the `setvbuf' function. */ #undef HAVE_SETVBUF -/* Define to 1 if you have the header file. */ -#undef HAVE_SGTTY_H - /* Define to 1 if you have the header file. */ #undef HAVE_SHADOW_H @@ -201,6 +213,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H @@ -237,12 +252,6 @@ /* Define to 1 if you have the `tcsetpgrp' function. */ #undef HAVE_TCSETPGRP -/* Define to 1 if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_TERMIO_H - /* Define to 1 if you have the header file. */ #undef HAVE_TTYENT_H @@ -258,6 +267,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_USERSEC_H +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIL_H + /* Logfile path */ #undef LOGFILEPATH @@ -297,15 +309,15 @@ /* Define to 1 if the `setpgrp' function takes no argument. */ #undef SETPGRP_VOID -/* The size of a `long', as computed by sizeof. */ -#undef SIZEOF_LONG - /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME +/* Defined if we trust reverse DNS */ +#undef TRUST_REVERSE_DNS + /* use tcp_wrappers libwrap */ #undef USE_LIBWRAP diff --git a/config.sub b/config.sub index 1dea9b7..6890099 100755 --- a/config.sub +++ b/config.sub @@ -1,9 +1,9 @@ #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002 Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -timestamp='2002-09-05' +timestamp='2003-08-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -118,7 +118,7 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*) + nto-qnx* | linux-gnu* | linux-dietlibc | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; @@ -228,13 +228,14 @@ case $basic_machine in | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ - | clipper \ + | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ - | ip2k \ + | ip2k | iq2000 \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ @@ -245,21 +246,23 @@ case $basic_machine in | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ + | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ - | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ - | tahoe | thumb | tic80 | tron \ + | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ @@ -294,7 +297,7 @@ case $basic_machine in | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ @@ -302,7 +305,7 @@ case $basic_machine in | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* \ + | ip2k-* | iq2000-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ @@ -315,21 +318,25 @@ case $basic_machine in | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipstx39 | mipstx39el \ - | none-* | np1-* | ns16k-* | ns32k-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ @@ -367,6 +374,9 @@ case $basic_machine in basic_machine=a29k-none os=-bsd ;; + amd64) + basic_machine=x86_64-pc + ;; amdahl) basic_machine=580-amdahl os=-sysv @@ -716,6 +726,10 @@ case $basic_machine in np1) basic_machine=np1-gould ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -758,18 +772,24 @@ case $basic_machine in pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; - pentiumii | pentium2) + pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; + pentium4) + basic_machine=i786-pc + ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - pentiumii-* | pentium2-*) + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; pn) basic_machine=pn-gould ;; @@ -828,6 +848,10 @@ case $basic_machine in sb1el) basic_machine=mipsisa64sb1el-unknown ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; sequent) basic_machine=i386-sequent ;; @@ -835,6 +859,9 @@ case $basic_machine in basic_machine=sh-hitachi os=-hms ;; + sh64) + basic_machine=sh64-unknown + ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks @@ -901,10 +928,6 @@ case $basic_machine in basic_machine=i386-sequent os=-dynix ;; - t3d) - basic_machine=alpha-cray - os=-unicos - ;; t3e) basic_machine=alphaev5-cray os=-unicos @@ -913,14 +936,18 @@ case $basic_machine in basic_machine=t90-cray os=-unicos ;; - tic4x | c4x*) - basic_machine=tic4x-unknown - os=-coff - ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; tx39) basic_machine=mipstx39-unknown ;; @@ -977,10 +1004,6 @@ case $basic_machine in basic_machine=hppa1.1-winbond os=-proelf ;; - windows32) - basic_machine=i386-pc - os=-windows32-msvcrt - ;; xps | xps100) basic_machine=xps100-honeywell ;; @@ -1027,7 +1050,7 @@ case $basic_machine in we32k) basic_machine=we32k-att ;; - sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele) + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) @@ -1106,18 +1129,19 @@ case $os in | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*) + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1129,8 +1153,10 @@ case $os in ;; esac ;; + -nto-qnx*) + ;; -nto*) - os=-nto-qnx + os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ @@ -1139,6 +1165,9 @@ case $os in -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; @@ -1224,6 +1253,12 @@ case $os in -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; -none) ;; *) @@ -1255,6 +1290,9 @@ case $basic_machine in arm*-semi) os=-aout ;; + c4x-* | tic4x-*) + os=-coff + ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 diff --git a/configure b/configure index e9d4b67..4395163 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.54. +# Generated by GNU Autoconf 2.57. # # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. @@ -36,7 +36,10 @@ PS2='> ' PS4='+ ' # NLS nuisances. -for as_var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_NUMERIC LC_MESSAGES LC_TIME +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME do if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var @@ -82,15 +85,15 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conftest.sh - echo "exit 0" >>conftest.sh - chmod +x conftest.sh - if (PATH="/nonexistent;."; conftest.sh) >/dev/null 2>&1; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi - rm -f conftest.sh + rm -f conf$$.sh fi @@ -840,7 +843,6 @@ if test -n "$ac_init_help"; then Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-64bit Allow 64bit compilation --with-port=PORT Specify port number [conserver] --with-base=PORT Base port for secondary channel [0] --with-master=MASTER Specify master server hostname [console] @@ -852,13 +854,13 @@ Optional Packages: --with-pidfile=PIDFILE Specify PID filepath [/var/run/conserver.pid] --with-maxmemb=MAXMEMB Specify maximum consoles per process [16] --with-timeout=TIMEOUT Specify connect() timeout in seconds [10] + --with-trustrevdns Trust reverse DNS information --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support --with-openssl[=PATH] Compile in OpenSSL support --with-dmalloc[=PATH] Compile in dmalloc support - --with-regex Use regular expressions in conserver.passwd --with-pam Enable PAM support Some influential environment variables: @@ -949,7 +951,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.54. Invocation command line was +generated by GNU Autoconf 2.57. Invocation command line was $ $0 $@ @@ -1001,24 +1003,54 @@ _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= +ac_configure_args0= +ac_configure_args1= ac_sep= -for ac_arg +ac_must_keep_next=false +for ac_pass in 1 2 do - case $ac_arg in - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n ) continue ;; - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - continue ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) - ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" - # Get rid of the leading space. - ac_sep=" " + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there @@ -1262,18 +1294,6 @@ MKDIR="mkdir -p -m 755" -echo "$as_me:$LINENO: checking whether to allow 64bit compilation" >&5 -echo $ECHO_N "checking whether to allow 64bit compilation... $ECHO_C" >&6 - -# Check whether --with-64bit or --without-64bit was given. -if test "${with_64bit+set}" = set; then - withval="$with_64bit" - with_64bit=yes -else - with_64bit=no -fi; -echo "$as_me:$LINENO: result: $with_64bit" >&5 -echo "${ECHO_T}$with_64bit" >&6 echo "$as_me:$LINENO: checking for port number specification" >&5 echo $ECHO_N "checking for port number specification... $ECHO_C" >&6 @@ -1588,6 +1608,31 @@ _ACEOF echo "${ECHO_T}10" >&6 fi; +echo "$as_me:$LINENO: checking whether to trust reverse DNS" >&5 +echo $ECHO_N "checking whether to trust reverse DNS... $ECHO_C" >&6 + +# Check whether --with-trustrevdns or --without-trustrevdns was given. +if test "${with_trustrevdns+set}" = set; then + withval="$with_trustrevdns" + case "$withval" in + yes) + cat >>confdefs.h <<\_ACEOF +#define TRUST_REVERSE_DNS 1 +_ACEOF + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi; + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -1897,8 +1942,10 @@ fi fi -test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5 -echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;} +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. @@ -1923,7 +1970,11 @@ ac_compiler=`set X $ac_compile; echo $2` cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ int main () @@ -1934,7 +1985,7 @@ main () } _ACEOF ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.exe" +ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. @@ -1953,27 +2004,39 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= -for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.*; do +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do test -f "$ac_file" || continue case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; - a.out ) # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - # FIXME: I believe we export ac_cv_exeext for Libtool --akim. - export ac_cv_exeext - break;; - * ) break;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; esac done else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + { { echo "$as_me:$LINENO: error: C compiler cannot create executables -check \`config.log' for details." >&5 +See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables -check \`config.log' for details." >&2;} +See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi @@ -2000,9 +2063,11 @@ if test "$cross_compiling" != yes; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'." >&5 +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'." >&2;} +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi @@ -2010,7 +2075,7 @@ fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 -rm -f a.out a.exe conftest$ac_cv_exeext +rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. @@ -2041,8 +2106,10 @@ for ac_file in conftest.exe conftest conftest.*; do esac done else - { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5 -echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;} + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -2060,7 +2127,11 @@ if test "${ac_cv_objext+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ int main () @@ -2085,9 +2156,12 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 done else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5 -echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;} +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -2104,7 +2178,11 @@ if test "${ac_cv_c_compiler_gnu+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ int main () @@ -2132,7 +2210,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_compiler_gnu=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -2152,7 +2231,11 @@ if test "${ac_cv_prog_cc_g+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ int main () @@ -2177,7 +2260,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_prog_cc_g=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -2208,7 +2292,11 @@ else ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include #include #include @@ -2271,7 +2359,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext done @@ -2322,7 +2411,11 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 do cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include $ac_declaration int @@ -2348,13 +2441,18 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 : else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + continue fi rm -f conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_declaration int main () @@ -2379,7 +2477,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext done @@ -2392,7 +2491,8 @@ fi else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext ac_ext=c @@ -2514,15 +2614,15 @@ else echo "${ECHO_T}no, using $LN_S" >&6 fi -echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5 -echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: - @echo 'ac_maketemp="${MAKE}"' + @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` @@ -2568,12 +2668,22 @@ for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" -#include +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -2596,7 +2706,8 @@ if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Broken: fails on valid input. continue fi @@ -2606,7 +2717,11 @@ rm -f conftest.err conftest.$ac_ext # can be detected and how. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -2630,7 +2745,8 @@ if test -z "$ac_cpp_err"; then continue else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Passes both tests. ac_preproc_ok=: break @@ -2659,12 +2775,22 @@ for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" -#include +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -2687,7 +2813,8 @@ if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Broken: fails on valid input. continue fi @@ -2697,7 +2824,11 @@ rm -f conftest.err conftest.$ac_ext # can be detected and how. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -2721,7 +2852,8 @@ if test -z "$ac_cpp_err"; then continue else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Passes both tests. ac_preproc_ok=: break @@ -2734,8 +2866,10 @@ rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else - { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5 -echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -2766,7 +2900,11 @@ echo "$as_me:$LINENO: checking for AIX" >&5 echo $ECHO_N "checking for AIX... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #ifdef _AIX yes #endif @@ -2794,7 +2932,11 @@ if test "${ac_cv_c_const+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ int main () @@ -2865,7 +3007,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_c_const=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -2901,6 +3044,7 @@ echo "${ECHO_T}no" >&6 fi + echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then @@ -2908,43 +3052,54 @@ if test "${ac_cv_header_stdc+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include #include #include #include +int +main () +{ + + ; + return 0; +} _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_header_stdc=no +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF @@ -2962,7 +3117,11 @@ if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF @@ -2983,13 +3142,18 @@ if test $ac_cv_header_stdc = yes; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else -# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) @@ -3022,7 +3186,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ( exit $ac_status ) ac_cv_header_stdc=no fi @@ -3061,7 +3226,11 @@ if eval "test \"\${$as_ac_Header+set}\" = set"; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> @@ -3081,7 +3250,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + eval "$as_ac_Header=no" fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -3098,476 +3268,6 @@ fi done -echo "$as_me:$LINENO: checking for long" >&5 -echo $ECHO_N "checking for long... $ECHO_C" >&6 -if test "${ac_cv_type_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -int -main () -{ -if ((long *) 0) - return 0; -if (sizeof (long)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_long=yes -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_cv_type_long=no -fi -rm -f conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 -echo "${ECHO_T}$ac_cv_type_long" >&6 - -echo "$as_me:$LINENO: checking size of long" >&5 -echo $ECHO_N "checking size of long... $ECHO_C" >&6 -if test "${ac_cv_sizeof_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test "$ac_cv_type_long" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` -fi -rm -f conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` -fi -rm -f conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_lo= ac_hi= -fi -rm -f conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_long=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77" >&5 -echo "$as_me: error: cannot compute sizeof (long), 77" >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling" >&5 -echo "$as_me: error: cannot run test program while cross compiling" >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -long longval () { return (long) (sizeof (long)); } -unsigned long ulongval () { return (long) (sizeof (long)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (long))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (long)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (long)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_long=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77" >&5 -echo "$as_me: error: cannot compute sizeof (long), 77" >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_long=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 -echo "${ECHO_T}$ac_cv_sizeof_long" >&6 -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF - - -if test "$ac_cv_sizeof_long" -gt 4; then - if test "$with_64bit" != "yes"; then - { { echo "$as_me:$LINENO: error: cannot build on >32bit systems (to override use --with-64bit)" >&5 -echo "$as_me: error: cannot build on >32bit systems (to override use --with-64bit)" >&2;} - { (exit 1); exit 1; }; } - else - { echo "$as_me:$LINENO: WARNING: building a 64bit version of conserver - good luck!" >&5 -echo "$as_me: WARNING: building a 64bit version of conserver - good luck!" >&2;} - fi -fi - -echo "$as_me:$LINENO: checking for ANSI C header files" >&5 -echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 -if test "${ac_cv_header_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include -#include -#include -#include - -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_cv_header_stdc=yes -else - echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_header_stdc=no -fi -rm -f conftest.err conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then - : -else - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - exit(2); - exit (0); -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -( exit $ac_status ) -ac_cv_header_stdc=no -fi -rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 -echo "${ECHO_T}$ac_cv_header_stdc" >&6 -if test $ac_cv_header_stdc = yes; then - -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF - -fi - for ac_header in sys/ioctl.h do @@ -3586,7 +3286,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -3605,7 +3309,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -3617,7 +3322,11 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -3640,7 +3349,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -3653,14 +3363,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -3683,356 +3411,59 @@ fi done - -for ac_header in termios.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then +echo "$as_me:$LINENO: checking POSIX termios" >&5 +echo $ECHO_N "checking POSIX termios... $ECHO_C" >&6 +if test "${ac_cv_sys_posix_termios+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else - # Is the header compilable? -echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF + cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -#include <$ac_header> +/* confdefs.h. */ _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +/* SunOS 4.0.3 has termios.h but not the library calls. */ + tcgetattr(0, 0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_header_compiler=yes + ac_cv_sys_posix_termios=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_header_compiler=no -fi -rm -f conftest.$ac_objext conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6 +sed 's/^/| /' conftest.$ac_ext >&5 -# Is the header present? -echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include <$ac_header> -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes +ac_cv_sys_posix_termios=no fi -if test -z "$ac_cpp_err"; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_header_preproc=no +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -rm -f conftest.err conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6 +echo "$as_me:$LINENO: result: $ac_cv_sys_posix_termios" >&5 +echo "${ECHO_T}$ac_cv_sys_posix_termios" >&6 -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc in - yes:no ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; - no:yes ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; -esac -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=$ac_header_preproc" -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -if test "$ac_cv_header_termios_h" != "yes"; then - -for ac_header in termio.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 -else - # Is the header compilable? -echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_header_compiler=no -fi -rm -f conftest.$ac_objext conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6 - -# Is the header present? -echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include <$ac_header> -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_header_preproc=no -fi -rm -f conftest.err conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6 - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc in - yes:no ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; - no:yes ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; -esac -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=$ac_header_preproc" -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - if test "$ac_cv_header_termio_h" != "yes"; then - -for ac_header in sgtty.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 -else - # Is the header compilable? -echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -ac_header_compiler=no -fi -rm -f conftest.$ac_objext conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6 - -# Is the header present? -echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include <$ac_header> -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_header_preproc=no -fi -rm -f conftest.err conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6 - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc in - yes:no ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; - no:yes ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; -esac -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=$ac_header_preproc" -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - if test "$ac_cv_header_sgtty_h" != "yes"; then - { { echo "$as_me:$LINENO: error: no usable terminal interface detected" >&5 -echo "$as_me: error: no usable terminal interface detected" >&2;} +if test "$ac_cv_sys_posix_termios" != "yes"; then + { { echo "$as_me:$LINENO: error: POSIX termios interface required" >&5 +echo "$as_me: error: POSIX termios interface required" >&2;} { (exit 1); exit 1; }; } - fi - fi fi @@ -4053,7 +3484,8 @@ fi -for ac_header in unistd.h getopt.h sys/vlimit.h sys/resource.h ttyent.h sys/ttold.h sys/uio.h sys/proc.h sys/ioctl_compat.h usersec.h sys/select.h stropts.h sys/audit.h shadow.h sys/time.h crypt.h sysexits.h types.h + +for ac_header in unistd.h getopt.h sys/vlimit.h sys/resource.h ttyent.h sys/ttold.h sys/uio.h sys/proc.h sys/ioctl_compat.h usersec.h sys/select.h stropts.h sys/audit.h shadow.h sys/time.h crypt.h sysexits.h types.h sys/sockio.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -4070,7 +3502,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -4089,7 +3525,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4101,7 +3538,11 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -4124,7 +3565,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -4137,14 +3579,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -4173,7 +3633,11 @@ if test "${ac_cv_header_time+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include #include #include @@ -4202,7 +3666,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_header_time=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_header_time=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4224,7 +3689,11 @@ if test "${ac_cv_header_sys_wait_h+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include #include #ifndef WEXITSTATUS @@ -4259,7 +3728,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_header_sys_wait_h=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_header_sys_wait_h=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4281,7 +3751,11 @@ if test "${ac_cv_type_mode_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default int main () @@ -4309,7 +3783,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_mode_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_mode_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4333,7 +3808,11 @@ if test "${ac_cv_type_signal+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include #include #ifdef signal @@ -4368,7 +3847,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_signal=void else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_signal=int fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4388,7 +3868,11 @@ if test "${ac_cv_type_pid_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default int main () @@ -4416,7 +3900,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_pid_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_pid_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4441,7 +3926,11 @@ if test "${ac_cv_type_sig_atomic_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include int @@ -4470,7 +3959,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_sig_atomic_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_sig_atomic_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4495,7 +3985,11 @@ if test "${ac_cv_type_in_addr_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include @@ -4525,7 +4019,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_in_addr_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_in_addr_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4547,7 +4042,11 @@ if test "${ac_cv_type_socklen_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include @@ -4577,7 +4076,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_socklen_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_socklen_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4593,6 +4093,52 @@ _ACEOF fi +echo "$as_me:$LINENO: checking for sa_len in struct sockaddr" >&5 +echo $ECHO_N "checking for sa_len in struct sockaddr... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +struct sockaddr s; s.sa_len=0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SA_LEN 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + # Make sure we can run config.sub. $ac_config_sub sun4 >/dev/null 2>&1 || @@ -4662,7 +4208,11 @@ else LIBS="-lxnet $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -4694,7 +4244,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_xnet_t_error=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_xnet_t_error=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -4725,7 +4276,11 @@ else LIBS="-lsec $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -4757,7 +4312,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_sec_getspnam=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_sec_getspnam=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -4793,7 +4349,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -4812,7 +4372,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -4824,7 +4385,11 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -4847,7 +4412,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -4860,14 +4426,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -4902,31 +4486,44 @@ if eval "test \"\${$as_ac_var+set}\" = set"; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. */ -#include + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); -char (*f) (); - -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else -f = $ac_func; +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != $ac_func; ; return 0; } @@ -4946,7 +4543,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -4973,7 +4571,11 @@ else ac_cv_search_socket=no cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -5005,7 +4607,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_search_socket="none required" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_socket" = no; then @@ -5013,7 +4616,11 @@ if test "$ac_cv_search_socket" = no; then LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -5046,7 +4653,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext done @@ -5069,7 +4677,11 @@ else ac_cv_search_gethostbyname=no cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -5101,7 +4713,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_search_gethostbyname="none required" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_gethostbyname" = no; then @@ -5109,7 +4722,11 @@ if test "$ac_cv_search_gethostbyname" = no; then LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -5142,7 +4759,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext done @@ -5165,7 +4783,11 @@ else ac_cv_search_crypt=no cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -5197,7 +4819,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_search_crypt="none required" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_crypt" = no; then @@ -5205,7 +4828,11 @@ if test "$ac_cv_search_crypt" = no; then LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -5238,7 +4865,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext done @@ -5290,7 +4918,11 @@ echo "$as_me:$LINENO: checking tcpd.h usability" >&5 echo $ECHO_N "checking tcpd.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include _ACEOF @@ -5309,7 +4941,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -5321,7 +4954,11 @@ echo "$as_me:$LINENO: checking tcpd.h presence" >&5 echo $ECHO_N "checking tcpd.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -5344,7 +4981,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -5357,14 +4995,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: tcpd.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: tcpd.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: tcpd.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: tcpd.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: tcpd.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: tcpd.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: tcpd.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: tcpd.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: tcpd.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: tcpd.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: tcpd.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: tcpd.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for tcpd.h" >&5 echo $ECHO_N "checking for tcpd.h... $ECHO_C" >&6 @@ -5383,7 +5039,11 @@ if test $ac_cv_header_tcpd_h = yes; then echo $ECHO_N "checking for TCP wrappers library -lwrap... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include int allow_severity = 0; int deny_severity = 0; @@ -5410,22 +5070,73 @@ 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 - cat >>confdefs.h <<\_ACEOF + cat >>confdefs.h <<\_ACEOF #define USE_LIBWRAP 1 _ACEOF - CONSLIBS="$CONSLIBS -lwrap" - CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" - CONSCPPFLAGS="$CONSCPPFLAGS $WRAPCPPFLAGS" + CONSLIBS="$CONSLIBS -lwrap" + CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" + CONSCPPFLAGS="$CONSCPPFLAGS $WRAPCPPFLAGS" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + LIBS="$LIBS -lnsl" + echo "$as_me:$LINENO: checking for TCP wrappers library -lwrap with -lnsl" >&5 +echo $ECHO_N "checking for TCP wrappers library -lwrap with -lnsl... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + int allow_severity = 0; + int deny_severity = 0; + +int +main () +{ +hosts_access((void *)0) + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define USE_LIBWRAP 1 +_ACEOF + + CONSLIBS="$CONSLIBS -lwrap -lnsl" + CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" + CONSCPPFLAGS="$CONSCPPFLAGS $WRAPCPPFLAGS" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi - +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi LIBS="$oLIBS" @@ -5470,7 +5181,11 @@ echo "$as_me:$LINENO: checking openssl/ssl.h usability" >&5 echo $ECHO_N "checking openssl/ssl.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include _ACEOF @@ -5489,7 +5204,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -5501,7 +5217,11 @@ echo "$as_me:$LINENO: checking openssl/ssl.h presence" >&5 echo $ECHO_N "checking openssl/ssl.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -5524,7 +5244,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -5537,14 +5258,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: openssl/ssl.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: openssl/ssl.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: openssl/ssl.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for openssl/ssl.h" >&5 echo $ECHO_N "checking for openssl/ssl.h... $ECHO_C" >&6 @@ -5563,7 +5302,11 @@ if test $ac_cv_header_openssl_ssl_h = yes; then echo $ECHO_N "checking for openssl libraries -lssl and -lcrypto... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include int @@ -5595,7 +5338,8 @@ _ACEOF have_openssl=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -5648,7 +5392,11 @@ echo "$as_me:$LINENO: checking dmalloc.h usability" >&5 echo $ECHO_N "checking dmalloc.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include _ACEOF @@ -5667,7 +5415,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -5679,7 +5428,11 @@ echo "$as_me:$LINENO: checking dmalloc.h presence" >&5 echo $ECHO_N "checking dmalloc.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -5702,7 +5455,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -5715,14 +5469,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: dmalloc.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: dmalloc.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: dmalloc.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: dmalloc.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: dmalloc.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: dmalloc.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for dmalloc.h" >&5 echo $ECHO_N "checking for dmalloc.h... $ECHO_C" >&6 @@ -5741,7 +5513,11 @@ if test $ac_cv_header_dmalloc_h = yes; then echo $ECHO_N "checking for dmalloc libraries -ldmalloc... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include int @@ -5773,7 +5549,8 @@ _ACEOF have_dmalloc=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -5793,107 +5570,6 @@ fi; -echo "$as_me:$LINENO: checking for POSIX regex" >&5 -echo $ECHO_N "checking for POSIX regex... $ECHO_C" >&6 - -# Check whether --with-regex or --without-regex was given. -if test "${with_regex+set}" = set; then - withval="$with_regex" - if test "$withval" = yes; then - if test "$cross_compiling" = yes; then - have_posix_regex=unknown -else - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" - - #include - #include - main() { regex_t r; regmatch_t rm; char *text = "xabcy"; - if (regcomp(&r, "abc", 0)) exit(1); - if (regexec(&r, text, 1, &rm, 0)) exit(1); - if (rm.rm_so != 1) exit(1); /* check for correct offset */ - exit(0); } - -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - have_posix_regex=yes -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -( exit $ac_status ) -have_posix_regex=no -fi -rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi - if test $have_posix_regex = yes; then - echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 - cat >>confdefs.h <<\_ACEOF -#define HAVE_POSIX_REGCOMP 1 -_ACEOF - - elif test $have_posix_regex = unknown; then - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" - - #include - #include -int -main () -{ -regex_t *r; regfree(r); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 - cat >>confdefs.h <<\_ACEOF -#define HAVE_POSIX_REGCOMP 1 -_ACEOF - -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -fi -rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext - else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 - fi - else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 - fi -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi; echo "$as_me:$LINENO: checking for PAM support" >&5 echo $ECHO_N "checking for PAM support... $ECHO_C" >&6 @@ -5918,7 +5594,11 @@ echo "$as_me:$LINENO: checking security/pam_appl.h usability" >&5 echo $ECHO_N "checking security/pam_appl.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include _ACEOF @@ -5937,7 +5617,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -5949,7 +5630,11 @@ echo "$as_me:$LINENO: checking security/pam_appl.h presence" >&5 echo $ECHO_N "checking security/pam_appl.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -5972,7 +5657,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -5985,14 +5671,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: security/pam_appl.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: security/pam_appl.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: security/pam_appl.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for security/pam_appl.h" >&5 echo $ECHO_N "checking for security/pam_appl.h... $ECHO_C" >&6 @@ -6011,7 +5715,11 @@ if test $ac_cv_header_security_pam_appl_h = yes; then echo $ECHO_N "checking for PAM library -lpam... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6049,7 +5757,8 @@ _ACEOF CONSLIBS="$CONSLIBS -lpam" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + LIBS="$LIBS -ldl" echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 @@ -6057,7 +5766,11 @@ echo "${ECHO_T}no" >&6 echo $ECHO_N "checking for PAM library -lpam with -ldl... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6095,7 +5808,8 @@ _ACEOF CONSLIBS="$CONSLIBS -lpam -ldl" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -6119,36 +5833,213 @@ fi; +for ac_header in pty.h libutil.h util.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done +echo "$as_me:$LINENO: checking for openpty in -lutil" >&5 +echo $ECHO_N "checking for openpty in -lutil... $ECHO_C" >&6 +if test "${ac_cv_lib_util_openpty+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lutil $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char openpty (); +int +main () +{ +openpty (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_util_openpty=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_util_openpty=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_util_openpty" >&5 +echo "${ECHO_T}$ac_cv_lib_util_openpty" >&6 +if test $ac_cv_lib_util_openpty = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBUTIL 1 +_ACEOF + + LIBS="-lutil $LIBS" + +fi - - - - - - - - - - - - - - - - - - - - - - - - - -for ac_func in getopt strerror getrlimit getsid setsid getuserattr setgroups tcgetpgrp tcsetpgrp tcgetattr tcsetattr tcsendbreak setpgrp getutent setttyent getspnam setlinebuf setvbuf ptsname grantpt unlockpt sigaction setsockopt getdtablesize putenv memset memcpy memcmp sysconf getpassphrase getlogin +for ac_func in openpty do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -6158,31 +6049,44 @@ if eval "test \"\${$as_ac_var+set}\" = set"; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. */ -#include + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); -char (*f) (); - -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else -f = $ac_func; +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != $ac_func; ; return 0; } @@ -6202,7 +6106,124 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_func in getopt strerror getrlimit getsid setsid getuserattr setgroups tcgetpgrp tcsetpgrp tcgetattr tcsetattr tcsendbreak setpgrp getutent setttyent getspnam setlinebuf setvbuf ptsname grantpt unlockpt sigaction setsockopt getdtablesize putenv memset memcpy memcmp memmove sysconf getlogin inet_aton +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6229,7 +6250,11 @@ echo "$as_me: error: cannot check setpgrp when cross compiling" >&2;} else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #if HAVE_UNISTD_H # include #endif @@ -6260,7 +6285,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ( exit $ac_status ) ac_cv_func_setpgrp_void=yes fi @@ -6284,31 +6310,44 @@ if test "${ac_cv_func_strcasecmp+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char strcasecmp (); below. */ -#include + which can conflict with char strcasecmp (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strcasecmp (); -char (*f) (); - -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_strcasecmp) || defined (__stub___strcasecmp) choke me #else -f = strcasecmp; +char (*f) () = strcasecmp; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != strcasecmp; ; return 0; } @@ -6328,7 +6367,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_func_strcasecmp=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_func_strcasecmp=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6349,31 +6389,44 @@ if test "${ac_cv_func_stricmp+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char stricmp (); below. */ -#include + which can conflict with char stricmp (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char stricmp (); -char (*f) (); - -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_stricmp) || defined (__stub___stricmp) choke me #else -f = stricmp; +char (*f) () = stricmp; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != stricmp; ; return 0; } @@ -6393,7 +6446,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_func_stricmp=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_func_stricmp=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6433,7 +6487,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -6452,7 +6510,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -6464,7 +6523,11 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 @@ -6487,7 +6550,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -6500,14 +6564,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -6539,7 +6621,11 @@ else LIBS="-lbsm $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6571,7 +6657,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_bsm_getaudit=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_bsm_getaudit=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6600,31 +6687,44 @@ if eval "test \"\${$as_ac_var+set}\" = set"; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. */ -#include + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); -char (*f) (); - -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else -f = $ac_func; +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != $ac_func; ; return 0; } @@ -6644,7 +6744,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6710,7 +6811,7 @@ _ACEOF t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache -if cmp -s $cache_file confcache; then :; else +if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file @@ -6770,6 +6871,8 @@ cat >$CONFIG_STATUS <<_ACEOF # configure, is in config.log if it exists. debug=false +ac_cs_recheck=false +ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF @@ -6804,7 +6907,10 @@ PS2='> ' PS4='+ ' # NLS nuisances. -for as_var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_NUMERIC LC_MESSAGES LC_TIME +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME do if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var @@ -6850,15 +6956,15 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conftest.sh - echo "exit 0" >>conftest.sh - chmod +x conftest.sh - if (PATH="/nonexistent;."; conftest.sh) >/dev/null 2>&1; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi - rm -f conftest.sh + rm -f conf$$.sh fi @@ -7021,7 +7127,7 @@ _ASBOX cat >&5 <<_CSEOF This file was extended by $as_me, which was -generated by GNU Autoconf 2.54. Invocation command line was +generated by GNU Autoconf 2.57. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -7061,6 +7167,7 @@ Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit + -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] @@ -7080,7 +7187,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.54, +configured by $0, generated by GNU Autoconf 2.57, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 @@ -7117,12 +7224,9 @@ do case $ac_option in # Handling of the options. _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion" - exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;; -_ACEOF cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) @@ -7144,6 +7248,9 @@ Try \`$0 --help' for more information." >&2;} $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 @@ -7158,6 +7265,20 @@ Try \`$0 --help' for more information." >&2;} shift done +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + _ACEOF @@ -7191,6 +7312,9 @@ if $ac_need_defaults; then test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { @@ -7199,17 +7323,17 @@ $debug || } # Create a (secure) tmp directory for tmp files. -: ${TMPDIR=/tmp} + { - tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { - tmp=$TMPDIR/cs$$-$RANDOM + tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { - echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } @@ -7667,7 +7791,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then - if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else @@ -7736,8 +7860,11 @@ ac_clean_files=$ac_clean_files_save # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null - $SHELL $CONFIG_STATUS || ac_cs_success=false + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. diff --git a/configure.in b/configure.in index fc4250e..481a2f1 100644 --- a/configure.in +++ b/configure.in @@ -10,10 +10,12 @@ AH_TEMPLATE([MAXMEMB], [Number of consoles per child process]) AH_TEMPLATE([CONNECTTIMEOUT], [TCP connection timeout]) AH_TEMPLATE([PIDFILE], [pidfile to write to]) AH_TEMPLATE([USE_LIBWRAP], [use tcp_wrappers libwrap]) -AH_TEMPLATE([HAVE_POSIX_REGCOMP], [have POSIX regcomp]) +dnl AH_TEMPLATE([HAVE_POSIX_REGCOMP], [have POSIX regcomp]) AH_TEMPLATE([HAVE_PAM], [have PAM support]) AH_TEMPLATE([HAVE_OPENSSL], [have openssl support]) AH_TEMPLATE([HAVE_DMALLOC], [have dmalloc support]) +AH_TEMPLATE([HAVE_SA_LEN],[Defined if sa_len member exists in struct sockaddr]) +AH_TEMPLATE([TRUST_REVERSE_DNS],[Defined if we trust reverse DNS]) dnl ### Normal initialization. ###################################### AC_INIT @@ -31,11 +33,18 @@ AC_SUBST(MKDIR) dnl ### Custom settings. ############################################ -AC_MSG_CHECKING(whether to allow 64bit compilation) -AC_ARG_WITH(64bit, - AC_HELP_STRING([--with-64bit],[Allow 64bit compilation]), - [with_64bit=yes], [with_64bit=no]) -AC_MSG_RESULT($with_64bit) +dnl AC_MSG_CHECKING(whether to allow 64bit compilation) +dnl AC_ARG_WITH(64bit, +dnl AC_HELP_STRING([--with-64bit],[Allow 64bit compilation]), +dnl [case "$withval" in +dnl yes) +dnl with_64bit=yes +dnl ;; +dnl *) +dnl with_64bit=no +dnl ;; +dnl esac], [with_64bit=no]) +dnl AC_MSG_RESULT($with_64bit) AC_MSG_CHECKING(for port number specification) AC_ARG_WITH(port, @@ -193,6 +202,19 @@ AC_ARG_WITH(timeout, [AC_DEFINE_UNQUOTED(CONNECTTIMEOUT, 10) AC_MSG_RESULT(10)]) +AC_MSG_CHECKING(whether to trust reverse DNS) +AC_ARG_WITH(trustrevdns, + AC_HELP_STRING([--with-trustrevdns],[Trust reverse DNS information]), + [case "$withval" in + yes) + AC_DEFINE(TRUST_REVERSE_DNS) + AC_MSG_RESULT(yes) + ;; + *) + AC_MSG_RESULT(no) + ;; + esac],[AC_MSG_RESULT(no)]) + dnl ### Check for compiler et al. ################################### AC_PROG_CC AC_PROG_INSTALL @@ -204,34 +226,25 @@ AC_AIX AC_C_CONST AC_C_PROTOTYPES -AC_CHECK_SIZEOF(long) -if test "$ac_cv_sizeof_long" -gt 4; then - if test "$with_64bit" != "yes"; then - AC_MSG_ERROR([cannot build on >32bit systems (to override use --with-64bit)]) - else - AC_MSG_WARN([building a 64bit version of conserver - good luck!]) - fi -fi +dnl AC_CHECK_SIZEOF(long) +dnl if test "$ac_cv_sizeof_long" -gt 4; then +dnl if test "$with_64bit" != "yes"; then +dnl AC_MSG_ERROR([cannot build on >32bit systems (to override use --with-64bit)]) +dnl else +dnl AC_MSG_WARN([building a 64bit version of conserver - good luck!]) +dnl fi +dnl fi dnl ### Checks for header files. ################################### AC_HEADER_STDC AC_CHECK_HEADERS(sys/ioctl.h) -dnl ### POSIX terminal I/O -AC_CHECK_HEADERS(termios.h) -if test "$ac_cv_header_termios_h" != "yes"; then - dnl ### SysV terminal I/O - AC_CHECK_HEADERS(termio.h) - if test "$ac_cv_header_termio_h" != "yes"; then - dnl ### BSD terminal I/O - AC_CHECK_HEADERS(sgtty.h) - if test "$ac_cv_header_sgtty_h" != "yes"; then - AC_MSG_ERROR([no usable terminal interface detected]) - fi - fi +AC_SYS_POSIX_TERMIOS +if test "$ac_cv_sys_posix_termios" != "yes"; then + AC_MSG_ERROR([POSIX termios interface required]) fi -AC_CHECK_HEADERS(unistd.h getopt.h sys/vlimit.h sys/resource.h ttyent.h sys/ttold.h sys/uio.h sys/proc.h sys/ioctl_compat.h usersec.h sys/select.h stropts.h sys/audit.h shadow.h sys/time.h crypt.h sysexits.h types.h) +AC_CHECK_HEADERS(unistd.h getopt.h sys/vlimit.h sys/resource.h ttyent.h sys/ttold.h sys/uio.h sys/proc.h sys/ioctl_compat.h usersec.h sys/select.h stropts.h sys/audit.h shadow.h sys/time.h crypt.h sysexits.h types.h sys/sockio.h) AC_HEADER_TIME AC_HEADER_SYS_WAIT AC_TYPE_MODE_T @@ -250,6 +263,14 @@ AC_CHECK_TYPE([socklen_t],[AC_DEFINE(HAVE_SOCKLEN_T,1, [Defined if socklen_t exists])],,[$ac_includes_default #include ]) +AC_MSG_CHECKING(for sa_len in struct sockaddr) +AC_TRY_COMPILE([#include + #include ], + [struct sockaddr s; s.sa_len=0;], + [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SA_LEN)], + [AC_MSG_RESULT(no)]) + dnl ### Host specific checks. ###################################### AC_CANONICAL_HOST @@ -299,12 +320,23 @@ AC_ARG_WITH(libwrap, int deny_severity = 0; ],[hosts_access((void *)0)], [AC_MSG_RESULT(yes) - AC_DEFINE(USE_LIBWRAP) - CONSLIBS="$CONSLIBS -lwrap" - CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" - CONSCPPFLAGS="$CONSCPPFLAGS $WRAPCPPFLAGS"], - [AC_MSG_RESULT(no)])],) - + AC_DEFINE(USE_LIBWRAP) + CONSLIBS="$CONSLIBS -lwrap" + CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" + CONSCPPFLAGS="$CONSCPPFLAGS $WRAPCPPFLAGS"], + [AC_MSG_RESULT(no) + LIBS="$LIBS -lnsl" + AC_MSG_CHECKING(for TCP wrappers library -lwrap with -lnsl) + AC_TRY_LINK([#include + int allow_severity = 0; + int deny_severity = 0; + ],[hosts_access((void *)0)], + [AC_MSG_RESULT(yes) + AC_DEFINE(USE_LIBWRAP) + CONSLIBS="$CONSLIBS -lwrap -lnsl" + CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" + CONSCPPFLAGS="$CONSCPPFLAGS $WRAPCPPFLAGS"], + [AC_MSG_RESULT(no)])])],) LIBS="$oLIBS" CPPFLAGS="$oCPPFLAGS" LDFLAGS="$oLDFLAGS" @@ -390,38 +422,38 @@ AC_ARG_WITH(dmalloc, dnl ### Check for needed functions. ################################ -dnl The following basically stollen from the less-358 distribution, but -dnl modified for my own purposes -AC_MSG_CHECKING(for POSIX regex) -AC_ARG_WITH(regex, - AC_HELP_STRING([--with-regex], - [Use regular expressions in conserver.passwd]), - [if test "$withval" = yes; then - AC_TRY_RUN([ - #include - #include - main() { regex_t r; regmatch_t rm; char *text = "xabcy"; - if (regcomp(&r, "abc", 0)) exit(1); - if (regexec(&r, text, 1, &rm, 0)) exit(1); - if (rm.rm_so != 1) exit(1); /* check for correct offset */ - exit(0); } - ],have_posix_regex=yes,have_posix_regex=no,have_posix_regex=unknown) - if test $have_posix_regex = yes; then - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_POSIX_REGCOMP) - elif test $have_posix_regex = unknown; then - AC_TRY_LINK([ - #include - #include ], - [regex_t *r; regfree(r);], - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_POSIX_REGCOMP)) - else - AC_MSG_RESULT(no) - fi - else - AC_MSG_RESULT(no) - fi],[AC_MSG_RESULT(no)]) +dnl dnl The following basically stollen from the less-358 distribution, but +dnl dnl modified for my own purposes +dnl AC_MSG_CHECKING(for POSIX regex) +dnl AC_ARG_WITH(regex, +dnl AC_HELP_STRING([--with-regex], +dnl [Use regular expressions in conserver.passwd]), +dnl [if test "$withval" = yes; then +dnl AC_TRY_RUN([ +dnl #include +dnl #include +dnl main() { regex_t r; regmatch_t rm; char *text = "xabcy"; +dnl if (regcomp(&r, "abc", 0)) exit(1); +dnl if (regexec(&r, text, 1, &rm, 0)) exit(1); +dnl if (rm.rm_so != 1) exit(1); /* check for correct offset */ +dnl exit(0); } +dnl ],have_posix_regex=yes,have_posix_regex=no,have_posix_regex=unknown) +dnl if test $have_posix_regex = yes; then +dnl AC_MSG_RESULT(yes) +dnl AC_DEFINE(HAVE_POSIX_REGCOMP) +dnl elif test $have_posix_regex = unknown; then +dnl AC_TRY_LINK([ +dnl #include +dnl #include ], +dnl [regex_t *r; regfree(r);], +dnl AC_MSG_RESULT(yes) +dnl AC_DEFINE(HAVE_POSIX_REGCOMP)) +dnl else +dnl AC_MSG_RESULT(no) +dnl fi +dnl else +dnl AC_MSG_RESULT(no) +dnl fi],[AC_MSG_RESULT(no)]) AC_MSG_CHECKING(for PAM support) AC_ARG_WITH(pam, @@ -451,8 +483,22 @@ AC_ARG_WITH(pam, AC_MSG_RESULT(no) fi],[AC_MSG_RESULT(no)]) +dnl Checks for pty allocation... +dnl According to the xemacs distribution: +dnl getpt() is the preferred pty allocation method on glibc systems. +dnl _getpty() is the preferred pty allocation method on SGI systems. +dnl grantpt(), unlockpt(), ptsname() are defined by Unix98. +dnl openpty() is the preferred pty allocation method on BSD and Tru64 systems. +dnl openpty() might be declared in: +dnl - pty.h (Tru64 or Linux) +dnl - libutil.h (FreeBSD) +dnl - util.h (NetBSD) +dnl Conserver doesn't support getpt() or _getpt() yet. +AC_CHECK_HEADERS(pty.h libutil.h util.h) +AC_CHECK_LIB(util, openpty) +AC_CHECK_FUNCS(openpty) -AC_CHECK_FUNCS(getopt strerror getrlimit getsid setsid getuserattr setgroups tcgetpgrp tcsetpgrp tcgetattr tcsetattr tcsendbreak setpgrp getutent setttyent getspnam setlinebuf setvbuf ptsname grantpt unlockpt sigaction setsockopt getdtablesize putenv memset memcpy memcmp sysconf getpassphrase getlogin) +AC_CHECK_FUNCS(getopt strerror getrlimit getsid setsid getuserattr setgroups tcgetpgrp tcsetpgrp tcgetattr tcsetattr tcsendbreak setpgrp getutent setttyent getspnam setlinebuf setvbuf ptsname grantpt unlockpt sigaction setsockopt getdtablesize putenv memset memcpy memcmp memmove sysconf getlogin inet_aton) AC_FUNC_SETPGRP AC_CHECK_FUNC(strcasecmp, [AC_DEFINE(HAVE_STRCASECMP, 1, [Define if strcasecmp is available])], diff --git a/conserver.cf/INSTALL b/conserver.cf/INSTALL index 4a7c224..c57d1bd 100644 --- a/conserver.cf/INSTALL +++ b/conserver.cf/INSTALL @@ -1,19 +1,11 @@ The two files you need to set up are the conserver.cf and conserver.passwd files. See the sample conserver.cf and conserver.passwd files for examples. You can start with those and then modify extensively. -The man page for conserver.cf should explain that file with enough detail -to get you going. - -As for the conserver.passwd file, here are some instructions. The file -contains three fields seperated by colons: ::. -The field should either be an encrypted password or the special -string '*passwd*', which will cause the console server to do a getpwnam() -call. The field can be a comma seperated list of console names -(from conserver.cf) or the special string 'any'. Access for the user -is only granted to the hosts listed here (or all if 'any' is used). +The man page for conserver.cf and conserver.passwd should explain the +files with enough detail to get you going. That's about it. Good luck. # -# $Id: INSTALL,v 1.2 1999-08-24 13:45:00-07 bryan Exp $ +# $Id: INSTALL,v 1.3 2003-07-04 11:21:21-07 bryan Exp $ # diff --git a/conserver.cf/Makefile.in b/conserver.cf/Makefile.in index e31f753..db3abde 100644 --- a/conserver.cf/Makefile.in +++ b/conserver.cf/Makefile.in @@ -3,6 +3,7 @@ srcdir = @srcdir@ prefix = @prefix@ mandir = @mandir@ sysconfdir = @sysconfdir@ +exampledir = $(prefix)/share/examples/conserver ### Installation programs and flags INSTALL = @INSTALL@ @@ -24,5 +25,8 @@ install: $(MKDIR) $(DESTDIR)$(mandir)/man5 $(INSTALL) conserver.cf.man $(DESTDIR)$(mandir)/man5/conserver.cf.5 $(INSTALL) conserver.passwd.man $(DESTDIR)$(mandir)/man5/conserver.passwd.5 + $(MKDIR) $(DESTDIR)$(exampledir) + $(INSTALL) -m 0644 conserver.cf $(DESTDIR)$(exampledir) + $(INSTALL) -m 0644 conserver.passwd $(DESTDIR)$(exampledir) .PHONY: clean distclean install diff --git a/conserver.cf/conserver.cf b/conserver.cf/conserver.cf index d976dea..405b5cf 100644 --- a/conserver.cf/conserver.cf +++ b/conserver.cf/conserver.cf @@ -1,26 +1,54 @@ # -# $Id: conserver.cf,v 1.4 2001-06-28 10:24:01-07 bryan Exp $ +# $Id: conserver.cf,v 1.5 2003-07-04 11:05:04-07 bryan Exp $ # # The character '&' in logfile names are substituted with the console -# name. Any logfile name that doesn't begin with a '/' has LOGDIR -# prepended to it. So, most consoles will just have a '&' as the logfile -# name which causes /var/consoles/ to be used. +# name. # -LOGDIR=/var/consoles +default full { + rw *; +} +default * { + logfile /var/consoles/&; + timestamp ""; + include full; +} # # list of consoles we serve -# name : tty[@host] : baud[parity] : logfile : [mark-interval(m|h|d|l)][+] -# name : !host : port : logfile : [mark-interval(m|h|d|l)][+] -# name : |command : : logfile : [mark-interval(m|h|d|l)][+] # -tweety:!ts1:2002:&: -bambam:!ts1:2003:&: -shell:|::/dev/null: -telnet:|telnet host::/dev/null: -ttya:/dev/ttya:9600p:&: -%% +console tweety { + master localhost; + type host; + host ts1; + port 2002; +} +console bambam { + master localhost; + type host; + host ts1; + port 2003; +} +console shell { + master localhost; + logfile /dev/null; + type exec; + exec ""; +} +console telnet { + master localhost; + logfile /dev/null; + type exec; + exec telnet host; +} +console ttya { + master localhost; + type device; + device /dev/ttya; + baud 9600; + parity none; +} # # list of clients we allow -# {trusted|allowed|rejected} : machines # -allowed: 127.0.0.1 gnac.com +access * { + allowed 127.0.0.1 gnac.com; +} diff --git a/conserver.cf/conserver.cf.man b/conserver.cf/conserver.cf.man index f44c3dc..1e68f1c 100644 --- a/conserver.cf/conserver.cf.man +++ b/conserver.cf/conserver.cf.man @@ -1,239 +1,686 @@ -.\" $Id: conserver.cf.man,v 1.27 2003-04-08 13:46:12-07 bryan Exp $ -.\" @(#)constab.5 01/06/91 OSU CIS; Thomas A. Fine -.TH CONSERVER.CF 5 "Local" +.\" $Id: conserver.cf.man,v 1.41 2003-09-21 15:05:48-07 bryan Exp $ +.TH CONSERVER.CF 5 "2003-09-21" "conserver-8.0.0" "conserver" .SH NAME -conserver.cf \- console configuration file for conserver(8) -.SH SYNOPSIS -.br -.BI \s-1LOGDIR\s0= logdirectory -.br -.BI \s-1TIMESTAMP\s0= timestamp-spec -.br -.BI \s-1BREAK\s0\fIn\fP= break-spec -.br -\fIname\fP:\fIdevice\fP[@\fIconserver\fP]:\fIbaud\fP:\fIlogfile\fP:\fItimestamp-spec\fP:\fIbreak\fP -.br -\fIname\fP:!\fItermserver\fP[@\fIconserver\fP]:\fIport\fP:\fIlogfile\fP:\fItimestamp-spec\fP:\fIbreak\fP -.br -\fIname\fP:|\fIcommand\fP[@\fIconserver\fP]::\fIlogfile\fP:\fItimestamp-spec\fP:\fIbreak\fP -.br -\fB%%\fP -.br -\fIaccess\fP: \fIhosts\fP +conserver.cf \- console configuration file for +.BR conserver (8) .SH DESCRIPTION -.B Conserver.cf -is the configuration file for -.BR conserver (8). -It is read once upon startup; -modifications to the file take effect only upon restarting \fBconserver\fP. +The format of the conserver.cf file is made up of named blocks of +keyword/value pairs, comments, and optional whitespace for formatting +flexibility. +The block types as well as the keywords are pre-defined and +explained in the +.B \s-1BLOCKS\s0 +section. +A comment is an unquoted pound-sign +to a newline. +See the +.B \s-1PARSER\s0 +section for full details on whitespace and quoting. .PP -Blank lines and comment lines (those beginning with a ``#'' and -optional leading whitespace) are ignored. Non-ignored lines -beginning with whitespace are considered continuations of the -previous line. This allows you to span one logical line over -many physical lines and insert comments wherever appropriate. -.PP -The first section of the file has logical lines that are separated into -six colon-separated fields. Leading and trailing white space in each -field is ignored. -.TP -.I name -the unique name by which this connection is referred to -when using the \fBconsole\fP program. -This is typically the name of the host whose console is being monitored. -.TP -.I device -the full path name of the device for this line. -The \fIbaud\fP rate is the speed and parity for this console. -Speed may be given as an integer, -parity only requires the first letter of any of: even, odd, mark, space, none. -For historical reasons, `p' can also be used for no parity. -.TP -.BI ! termserver -the hostname of the terminal server to connect to. -A socket connection will be made to port \fIport\fP (an integer). -.TP -.BI | command -the command to invoke on the console server. -.PP -\fIdevice\fP, !\fItermserver\fP, and |\fIcommand\fP may be followed by -a remote console server name in the form ``\fB@\fP\fIconserver\fP'', -in which case the conserver daemon will send connections for \fIname\fP -to the conserver running on the host named \fIconserver\fP. -When the ``\fB@\fP\fIconserver\fP'' notation is used, -\fBconserver\fP recognizes consoles it should manage locally -by comparing the IP address of \fIconserver\fP -against the IP address of the name returned by gethostname(). -Thus, it will recognize host aliases, but not names that map to -different IP addresses that may exist on the same host, -so care must be used in specifying the hostname. -Since \fBconserver\fP does recognize its own hostname, -the same cf file may be used by all servers in a network -if every console line includes a ``\fB@\fP\fIconserver\fP'' specification. -.TP -.I logfile -the full path name of file where all output from -this host is logged. Any occurrence of `&' will be replaced with -\fIname\fP. Any path that doesn't begin with a `/' will -have \fIlogdirectory\fP (as specified in the nearest preceding -\fB\s-1LOGDIR=\s0\fP -line) prepended to it. If the field is empty, no logging will occur. -.TP -.I timestamp-spec -specifies the time between -timestamps applied to the console log file and -whether to log read/write connection actions. -The format of the specification is -[\fImark-interval\fP[\fBm\fP|\fBh\fP|\fBd\fP|\fBl\fP]][\fBa\fP][\fBb\fP]. -The timestamps look like `[-- MARK -- Mon Jan 25 14:46:56 1999]'. -The `\fBm\fP', `\fBh\fP', and `\fBd\fP' tags specify -`minutes' (the default), `hours', and `days'. The `\fBl\fP' tag -specifies `lines' and will cause timestamps of the form -`[Mon Jan 25 14:46:56 PST 1999]' to -be placed every \fImark-interval\fP lines (a newline character signifies -a new line). So, `5h' specifies every five hours and `2l' specifies every -two lines. -An `\fBa\fP' can be specified to add logs of -`attached', `detached', and `bumped' actions, -including the user's name and the host from which the -\fBconsole\fP connection was made, -to the logfile. -A `\fBb\fP' can be specified to add logging of break sequences sent -to the console. +Let me first show you a sample block with a couple of keyword/value +pairs to make the description a bit simpler to understand. .IP -A default \fItimestamp-spec\fP can be specified by using the -\fB\s-1TIMESTAMP=\s0\fP syntax. -All consoles below the \fB\s-1TIMESTAMP=\s0\fP line will use that -\fItimestamp-spec\fP unless overridden on a per-line basis, -and until superseded by another \fB\s-1TIMESTAMP=\s0\fP line. -To turn off marks for a specific -console, use a \fImark-interval\fP of zero. -.TP -.I break -specifies which break sequence to use. The default value is `1'. -Values of `0' thru `9' are valid. A value of `0' will unset the -default break sequence, which will cause the \fB^Ecl0\fP sequence to do -nothing. +.ft CR +.nf +console simple { master localhost; type exec; rw *; } +.fi +.ft .PP -The \fIbreak-spec\fP sequences are defined using -the \fB\s-1BREAK\s0\fIn\fB=\fR -syntax where \fIn\fP is a number from 1 to 9. -There are three builtin defaults: ``\s-1BREAK1\s0=\\z'', -``\s-1BREAK2\s0=\\r~^b'', -and ``\s-1BREAK3\s0=#.reset -x\\r''. The values of -the \fB\s-1BREAK\s0\fIn\fR -sequences are simple characters strings with the exception of `\\' and -`^': +This is actually a fully functional conserver.cf file (if certain +conditions are met...and if you can list those conditions, you can +probably can skip to the +.B \s-1BLOCKS\s0 +section). +.PP +Our example is made of up of a console-block named ``simple'' with three +keyword/value pairs. +What this does is define a console named ``simple'', +makes the master of that console the host ``localhost'', makes the type +an exec-style console, and gives every user read/write permission. +This is the generic format of the file: +.IP +.ft CR +.nf +block-type block-name { keyword value; ... } +.fi +.ft +.PP +To show the addition of comments and whitespace, here is the example +reformatted (but functionally equivalent): +.IP +.ft CR +.nf +# define a console named "simple" +console simple { + # setting all required values... + master localhost; + type exec; # exec-style console + rw *; # allow any username +} +.fi +.ft +.SH PARSER +.PP +The parser has six characters that it considers special. +These are: ``{'', ``}'', ``;'', ``#'', ``\e'', and ``"''. +The first three (hereby called tokens) define the format of the +configuration blocks and are used as word +seperators, the next is the comment character, and the last two are +quoting characters. +.PP +Word seperation occurs when the parser encounters an unquoted token +and, in certain cases, whitespace. +Whitespace is only used as a word seperator when the parser is +looking for a block-type or keyword. +When it's looking for a block-name or value, whitespace is like any +other character, which allows you to embed whitespace in a block-name +or value without having to quote it. +Here is an example: +.IP +.ft CR +.nf +default my defs { rw *; include other defs ; } +.fi +.ft +.PP +The block-type is ``default'', the block-name is ``my defs'', and the value +for the keyword ``include'' is ``other defs''. +Whitespace around tokens are ignored so you get ``other defs'' +instead of ``other defs '' as the value. +.PP +The only way to use one of the special characters as part of a block-name +or value is to quote it. +.PP +Quoting is a simple matter of prefixing a character with a backslash or +surrounding a group of characters with double-quotes. +If a character is prefixed by a backslash, the next character is a +literal (so ``\e\e'' produces a ``\e'', ``\e"'' produces ``"'', ``\e{'' +produces a ``{'', etc.). +For double-quoted strings, all characters are literal except for ``\e"'', +which embeds a double-quote. +.PP +Adding a variety of quotes to our example without changing the meaning +of things, we have: +.IP +.ft CR +.nf +"defa"ult my\e defs { rw *; in\eclude "other defs" ; } +.fi +.ft +.SH BLOCKS +.TP 8 +.B access +.RI [ " hostname " | " ipaddr " ] +.br +Define an access block for the host named +.I hostname +or using the address +.IR ipaddr . +If the value of ``*'' is used, the access block will be applied to +all conserver hosts. +Access lists are used in a first match +fashion (top down), so order is important. +.RS +.TP 15 +.B admin +.RI [ " username" ,... +| "" ] +.br +Define a list of users making up the admin list for the console server. +If +.I username +matches a previously defined group name, all members of the previous +group are added to the admin list. +If the null string (``""'') is used, any +users previously defined for the console servers's admin list are removed. +.TP +.B allowed +.IR hostname ", ..." +.br +The list of hostnames are added to the ``allowed'' list, which grants +connections from the hosts but requires username authentication. +.TP +.B include +.I accessgroup +.br +The access lists defined using the name +.I accessgroup +are applied to the current access block. +The included access block must be previously defined. +.TP +.B rejected +.IR hostname ", ..." +.br +The list of hostnames are added to the ``rejected'' list, which rejects +connections from the hosts. +.TP +.B trusted +.IR hostname ", ..." +.br +The list of hostnames are added to the ``trusted'' list, which grants +connections from the hosts without username authentication. +.RE +.TP 8 +.B break +.I n +.br +Define a break sequence where 0 < +.I n +< 10. +Break sequences are accessed via the +.RI ``^El n '' +client escape sequence. +.RS +.TP 15 +.B delay +.I n +.br +Set the time delay for the +.B \ed +sequence to +.I n +milliseconds. +The default time delay is 250ms. +.TP +.B string +.I breakseq +.br +Assign the string +.IR breakseq +to the specified slot +.IR n . +A break sequence is a simple character string with the exception of `\e' +and `^': +.RS .sp .PD 0 -.IP \\\\a +.TP 6 +.B \ea alert -.IP \\\\b +.TP +.B \eb backspace -.IP \\\\f +.TP +.B \ed +0.33 second delay +.TP +.B \ef form-feed -.IP \\\\n +.TP +.B \en newline -.IP \\\\r +.TP +.B \er carriage-return -.IP \\\\t +.TP +.B \et tab -.IP \\\\v +.TP +.B \ev vertical-tab -.IP \\\\z +.TP +.B \ez serial break -.IP \\\\\\\\ +.TP +.B \e\e backslash -.IP \\\\^ +.TP +.B \e^ circumflex -.IP \\\\\fIooo\fP -octal representation of a character (where \fIooo\fP is one to three -octal digits) -.IP \\\\\fIc\fP -character \fIc\fP -.IP ^? +.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 -.IP ^\fIc\fP -control character (\fIc\fP is `and'ed with 0x1f) +.TP +.BI ^ c +control character +.RI ( c +is ``and''ed with 0x1f) .PD -.PP -This section is terminated with a `\fB%%\fP' token on a line by itself. -.PP -The next section of the file contains a list of hosts and addresses -which are allowed to connect to the console server. -.B Conserver -looks for the first match in the config file -for a client's IP address (or network), -or hostname (or domain) if it is able to do a reverse lookup on the IP address, -to determine the level of access to be granted. -Three levels of access may be specified: ``\fBtrust\fP'' (access is granted -without a password), ``\fBallow\fP'' (access is granted with a password), -and ``\fBrefuse\fP'' (access is not granted). Only the first character of -the word is important, so you can use any word that begins with -a ``\fBt\fP'', ``\fBa\fP'', or ``\fBr\fP''. -The access level is followed by a colon and a space-separated list of -addresses or host names. -Any number of any combination of these levels may be specified, -bearing in mind that conserver uses the first match for each incoming -client connection, so order is important. -.PP -Any complete suffix of a host name may be used to define access for all hosts -in that subdomain. -For example, `\fBcc.purdue.edu\fP' will allow `mentor.cc.purdue.edu' -and `mace.cc.purdue.edu', but not `pucc.purdue.edu' or `hack.purdue.edu'. -For IP addresses, optional netmask lengths may be specified -in CIDR `/' notation. -For example, `\fB192.168.1.0\fP' will allow the class C space of 192.168.1.0, -but `\fB192.168.1.0/25\fP' will allow -only the lower half of that same address space (192.168.1.0 thru 192.168.1.127). -.SH EXAMPLE -# name:path:baud:logfile:mark:break -.nf -LOGDIR=/tmp -# overriding the builtin BREAK3 sequence -BREAK3=#.reset\\r -# adding another break sequence -BREAK8=+++ -# -# This logs to /tmp/treelog...using BREAK8 -tree:/dev/ttyj0:9600e:&log::8 -# -# This logs to /tmp/fishlog... -fish:/dev/ttyj1:4800e:fishlog: -# -# Now we're defaulting to /var/tmp for logfiles... -LOGDIR=/var/tmp -# -# So, this is /var/tmp/birdlog with 1-hour timestamps -bird:/dev/ttyj2:4800m:&log:1h -# -# And this is /var/tmp/solarlog, using BREAK4, no timestamps -solar:|telnet solar::solarlog::4 -# -# Now things are all in /var/consoles/ -LOGDIR=/var/consoles -shell:|::&: -# -# These open connections to ports 2003 and 2004 of ts1 -# using BREAK2 and BREAK3 -tribe:!ts1:2003:&::2 -# This one also has 10-minute timestamps and activity logging -reptile:!ts1:2004:&:10ma:3 -# -# This opens /dev/ttyh0 if running on extra.cc.purdue.edu; -# otherwise, clients are redirected to that host. -mentor:/dev/ttyh0@extra.cc.purdue.edu:2400e:&: -%% -# -# access restrictions -# (note that the "badhost.cc.purdue.edu" entry must appear -# before the "cc.purdue.edu" entry if connections from -# "badhost" are to be rejected, since only the first match -# is used) -# -trust: console.cc.purdue.edu 128.210.7.90 -refuse: badhost.cc.purdue.edu -allow: cc.purdue.edu stat.cc.purdue.edu +.RE +.RE +.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 conserver hosts. +.RS +.TP 15 +.B defaultaccess +.RB [ " rejected " | " trusted " | " allowed " ] +.br +Set the default access permission for all hosts not matched by +an access list (see the +.B \-a +command-line flag). +.TP +.B daemonmode +.RB [ " yes " | " true " | " on " | " no " | " false " | " off " ] +.br +Set whether or not to become a daemon when run (see the +.B \-d +command-line flag). +.TP +.B logfile +.I filename +.br +Set the logfile to write to when in daemon mode (see the +.B \-L +command-line flag). +.TP +.B passwdfile +.I filename +.br +Set the password file location used for authentication (see the +.B \-P +command-line flag). +.TP +.B primaryport +.RI [ " number " | " name " ] +.br +Set the port used by the master conserver process (see the +.B \-p +command-line flag). +.TP +.B redirect +.RB [ " yes " | " true " | " on " | " no " | " false " | " off " ] +.br +Turn redirection on or off (see the +.B \-R +command-line flag). +.TP +.B reinitcheck +.I number +.br +Set the number of seconds used between reinitialization checks (see the +.B \-O +command-line flag). +.TP +.B secondaryport +.RI [ " number " | " name " ] +.br +Set the base port number used by child processes (see the +.B \-b +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 sslrequired +.RB [ " yes " | " true " | " on " | " no " | " false " | " off " ] +.br +Set whether or not encryption is required when talking to clients (see the +.B \-E +command-line flag). +.RE +.TP 8 +.B console +.I name +.br +Define a console identified as +.IR name . +The keywords are the same as the +.B default +block with the following addition. +.RS +.TP 15 +.B aliases +.RI [ " name" ", ..." +| "" ] +.br +Define a list of console aliases. +If the null string (``""'') is used, any +aliases previously defined for the console are removed. +.RE +.TP 8 +.B default +.I name +.br +Define a block of defaults identified as +.IR name . +If +.I name +is ``*'', the automatically applied default block is defined (basically +all consoles have an implicit ``include "*";'' at the begining +of their definition). +.RS +.TP 15 +.B baud +.RB [ " 300 " | " 600 " | " 1800 " | " 2400 " | " 4800" +.RB | " 9600 " | " 19200 " | " 38400 " | " 57600 " | " 115200 " ] +.br +Assign the baud rate to the console. +Only consoles of type ``device'' will use this value. +.TP +.B break +.I n +.br +Assign the break sequence +.I n +as the default for the console, which is used by +the ``^Ecl0'' client escape sequence. +.TP +.B device +.I filename +.br +Assign the serial device +.I filename +as the access to the console. +Only consoles of type ``device'' will use this value. +.TP +.B exec +.RI [ " command " +| "" ] +.br +Assign the string +.I command +as the command to access the console. +Conserver will run the command by +invoking ``/bin/sh -ce "\fIcommand\fP"''. +If the null string (``""'') is used or no +.B exec +keyword is specified, conserver will use the command ``/bin/sh -i''. +Only consoles of type ``device'' will use this value. +.TP +.B host +.I hostname +.br +Assign +.I hostname +as the host to connect to for accessing the console. +You must also set the +.B port +option as well. +Only consoles of type ``host'' will use this value. +.TP +.B include +.I default +.br +The default block defined using the name +.I default +is applied to the current console or default block. +The included default block must be previously defined. +.TP +.B logfile +.RI [ " filename " +| "" ] +.br +Assign the logfile specified by +.I filename +to the console. Any occurance of ``&'' in +.I filename +will be replaced with the name of the console. +If the null string (``""'') is used, the logfile name is unset and +no logging will occur. +.TP +.B master +.RI [ " hostname " | " ipaddr " ] +.br +Define which conserver host manages the console. +The host may be specified by +.I hostname +or using the address +.IR ipaddr . +.TP +.B options +.RI [ " option" ,... +| "" ] +.br +You can negate the option by prefixing it with a +.RB `` ! '' +character. +So, to turn off the +.B hupcl +flag, you would use +.BR !hupcl . +The following are valid +.IR option s: +.RS +.sp +.PD 0 +.TP 12 +.B ixon +Enable +.SM XON/XOFF +flow control on output. +Only consoles of type ``device'' or ``exec'' will use this value. +Default is +.BR ixon . +.TP +.B ixany +Enable any character to restart output. +Only consoles of type ``device'' or ``exec'' will use this value. +Default is +.BR !ixany . +.TP +.B ixoff +Enable +.SM XON/XOFF +flow control on input. +Only consoles of type ``device'' or ``exec'' will use this value. +Default is +.B ixoff +for consoles of type ``device'' and +.B !ixoff +for consoles of type ``exec''. +.TP +.B crtscts +Enable +.SM RTS/CTS +(hardware) flow control. +Only consoles of type ``device'' will use this value. +Default is +.BR !crtscts . +.TP +.B cstopb +Set two stop bits, rather than one. +Only consoles of type ``device'' will use this value. +Default is +.BR !cstopb . +.TP +.B hupcl +Lower modem control lines after last process closes the device (hang up). +Only consoles of type ``device'' will use this value. +Default is +.BR !hupcl . +.TP +.B ondemand +Initialize the console when a client requests a connection to the console. +When no clients are connected, bring the console down. +The conserver option +.B \-i +will set this flag for all consoles. +Default is +.BR !ondemand . +.TP +.B striphigh +Strip the high bit off all data coming from this console and all clients +connected to this console before processing occurs. +The conserver option +.B \-7 +will set this flag for all consoles. +Default is +.BR !stiphigh . +.TP +.B reinitoncc +Automatically reinitialize (``bring up'') a downed console when a client +connects. +Without this option, a client will be attached to the downed console +and will need to manually reinitialize the console with an escape sequence. +The conserver option +.B \-o +will set this flag for all consoles. +Default is +.BR !reinitoncc . +.TP +.B autoreinit +Allow this console to be automatically reinitialized if it unexpectedly +goes down. +If the console doesn't come back up, it is retried every minute. +A console of type ``exec'' that exits with a zero exit status is +automatically reinitialized regardless of this setting. +The conserver option +.B \-F +will +.B unset +this flag for all consoles. +Default is +.BR autoreinit . +.TP +.B unloved +Enable the sending of this console's output (prefixed with it's +name) to the daemon's stdout (or the logfile if in daemon mode) when no +clients are connected to the console. +The conserver option +.B \-u +will set this flag for all consoles. +Default is +.BR !unloved . +.PD +.RE +.TP +.B parity +.RB [ " even " | " mark " | " none " | " odd " | " space " ] +.br +Set the parity option for the console. +Only consoles of type ``device'' will use this value. +.TP +.B port +.RI [ " number " | " name " ] +.br +Set the port used to access the console. +The port may be specified as a +.I number +or a +.IR name , +in which case it will use +.BR getservbyname (3) +to look up a port number. +You must also set the +.B host +option as well. +Only consoles of type ``host'' will use this value. +.TP +.B ro +.RI [ " username" ,... +| "" ] +.br +Define a list of users making up the read-only access list +for the console. +If +.I username +matches a previously defined group name, all members of the previous +group are added to the read-only access list. +If the null string (``""'') is used, any +users previously defined for the console's read-only list are removed. +.TP +.B rw +.RI [ " username" ,... +| "" ] +.br +Define a list of users making up the read-write access list +for the console. +If +.I username +matches a previously defined group name, all members of the previous +group are added to the read-write access list. +If the null string (``""'') is used, any +users previously defined for the console's read-write list are removed. +.TP +.B timestamp +[ +.RB [ \fInumber\fP [ m | h | d | l ]][ a ][ b ] +| "" ] +.br +Specifies the time between timestamps applied to the console +log file and whether to log read/write connection actions. +The timestamps look like ``[-- MARK -- Mon Jan 25 14:46:56 1999]''. +The +.RB ` m ', +.RB ` h ', +and +.RB ` d ' +tags specify ``minutes'' (the default), ``hours'', and ``days''. +The +.RB ` l ' +tag specifies ``lines'' and will cause timestamps of the +form ``[Mon Jan 25 14:46:56 PST 1999]'' to +be placed every +.I number +lines (a newline character signifies a new line). +So, ``5h'' specifies every five hours and ``2l'' specifies every +two lines. +An +.RB ` a ' +can be specified to add logs of ``attached'', ``detached'', +and ``bumped'' actions, including the user's name and the host from which the +client connection was made. +A +.RB ` b ' +can be specified to add logging of break sequences sent to the console. +.TP +.B type +.RB [ " device " | " exec " | " host " ] +.br +Set the type of console. The type +.RB `` device '' +should be used for local serial ports (also set the +.B device +option), the type +.RB `` exec '' +should be used for command invocations (perhaps also set the +.B exec +option), and the type +.RB `` host '' +should be used for terminal servers and other socket-based +interaction (also set the +.B host +and +.B port +options). +.RE +.TP 8 +.B group +.I name +.br +Define a user group identified as +.I name +.RS +.TP 15 +.B users +.RI [ " username" ,... +| "" ] +.br +Define a list of users making up the group +.IR name . +If +.I username +matches a previously defined group name, all members of the previous +group are added to the current group. +If the null string (``""'') is used, any +users previously defined for this group are removed. +.RE +.SH AUTHORS +Bryan Stansell, conserver.com .SH "SEE ALSO" .BR console (1), .BR conserver.passwd (5), diff --git a/conserver.cf/conserver.passwd b/conserver.cf/conserver.passwd index 4c40453..6ff1016 100644 --- a/conserver.cf/conserver.passwd +++ b/conserver.cf/conserver.passwd @@ -1,3 +1,3 @@ -bryan:td1AgneGE3RsU:any -djs:*passwd*:any -todd:*passwd*:server1 +bryan:td1AgneGE3RsU +djs:*passwd* +todd:*passwd* diff --git a/conserver.cf/conserver.passwd.man b/conserver.cf/conserver.passwd.man index 6fad4fe..bdf000b 100644 --- a/conserver.cf/conserver.passwd.man +++ b/conserver.cf/conserver.passwd.man @@ -1,70 +1,83 @@ -.\" $Id: conserver.passwd.man,v 1.6 2002-09-23 14:15:53-07 bryan Exp $ -.TH CONSERVER.PASSWD 5 "Local" +.\" $Id: conserver.passwd.man,v 1.9 2003-07-04 13:20:52-07 bryan Exp $ +.TH CONSERVER.PASSWD 5 "2003-07-04" "conserver-8.0.0" "conserver" .SH NAME -conserver.passwd \- user access information for conserver(8) +conserver.passwd \- user access information for +.BR conserver (8) .SH SYNOPSIS -.br -\fIusername\fB:\fIpassword\fB:\fIconsoles\fR +.IB username : password .SH DESCRIPTION -The \fBconserver.passwd\fP file -is the user authentication and authorization file for +The +.B conserver.passwd +file is the user authentication and authorization file for .BR conserver (8). Upon each incoming client connection, -\fBconserver\fP opens and reads the \fBconserver.passwd\fP file, -so edits to the file take effect immediately. -It reads only until the first \fIusername\fP match. +.B conserver +opens and reads the +.B conserver.passwd +file, so edits to the file take effect immediately. +It reads only until the first +.I username +match. .PP Blank lines and comment lines (those beginning with a ``#'' and -optional leading whitespace) are ignored. Non-ignored lines -beginning with whitespace are considered continuations of the -previous line. This allows you to span one logical line over +optional leading whitespace) are ignored. +Non-ignored lines beginning with whitespace are considered +continuations of the previous line. +This allows you to span one logical line over many physical lines and insert comments wherever appropriate. .PP -Each logical line consists of three colon-separated fields. -Leading and trailing white space in each -field is ignored. +Each logical line consists of two colon-separated fields. +Leading and trailing white space in each field is ignored. .TP .I username the login name of the authorized user, -or the string ``\fB*any*\fP'' to match any user. -This is compared against the name sent by the \fBconsole\fP client, -based either on the user's identity or on the \fB\-l\fP option. -Since \fBconserver\fP only uses the first \fIusername\fP match, -an ``\fB*any*\fP'' entry will apply to any user +or the string +.RB `` *any* '' +to match any user. +This is compared against the name sent by the +.B console +client, based either on the user's identity or on the +.B \-l option. +Since +.B conserver +only uses the first +.I username +match, a +.RB `` *any* '' +entry will apply to any user without an entry earlier in the file. .TP .I password the encrypted password, -or the string ``\fB*passwd*\fP'' -to indicate that \fBconserver\fP should look up the user's password -in the system \fBpasswd\fP (or \fBshadow\fP) database. If PAM -support has been enabled (\fB--with-pam\fP), PAM lookups will be done instead -of \fBpasswd\fP (or \fBshadow\fP) lookups. +or the string +.RB `` *passwd* '' +to indicate that +.B conserver +should look up the user's password +in the system +.BR passwd " (or " shadow ") database." +If PAM support has been enabled +.RB ( --with-pam ), +PAM lookups will be done instead of +.BR passwd " (or " shadow ") lookups." If this field is empty, password checking is bypassed for this user. -.TP -.I consoles -a comma- and/or space-separated list of consoles -to which the user is permitted to connect, -or the string ``\fBany\fP'' to allow access to any console. -These names must match the console names in the \fBconserver.cf\fP file. -If regular expression support was compiled in using --with-regex, the -names here are treated as regular expressions. .SH EXAMPLE -.TP 30 -\fBmary:r71mXjfALB5Ak:any\fP -Mary may connect to any console if her password matches; +.TP 24 +.B mary:r71mXjfALB5Ak +Mary uses the password specified above; it does not matter whether she has a login on the conserver host. .TP -\fBfred:*passwd*:foo.example.com,bar.example.com\fP -Fred may connect only to the listed consoles, -and only with his regular login password on the conserver host. +.B fred:*passwd* +Fred may connect only with his regular login password on the conserver host. .TP -\fBbozo:*:\fP -Bozo is not allowed access to any consoles. +.B bozo:* +Bozo is only allowed to access a console if his password isn't used (since +it's invalid) which means he needs to come from a +.B trusted +host. .TP -\fB*any*:*passwd*:any\fP -Anyone not listed above may access any console -if they have a regular login and know the password. +.B *any*:*passwd* +Anyone not listed above uses their regular login and password. .SH "SEE ALSO" .BR console (1), .BR conserver.cf (5), @@ -73,4 +86,8 @@ if they have a regular login and know the password. .PP There is currently no way provided by the conserver package to generate the encrypted password strings -besides copying them from the system \fBpasswd\fP database. +besides copying them from the system +.B passwd +database or running +.BR crypt (3) +via C or perl or some other language that supports it. diff --git a/conserver.cf/test.cf b/conserver.cf/test.cf index ea04924..4159850 100644 --- a/conserver.cf/test.cf +++ b/conserver.cf/test.cf @@ -1,30 +1,45 @@ # dummy conserver config file # -# $Id: dummy.cf,v 4.3 92/07/27 12:23:59 ksb Exp $ -# -# 1. change the `/dev/ttya' to any tty device you can put a serial device on -# that you could talk to with kermit/cu. Put in the baud rate and parity. -# -# 2. change the `cc.purdue.edu' to your local domain. -# -# 3. !! do not leave this up, as it can give local users a root shell (login) -# !! for extended testing change the `|' to `|su - tst' where tst is a -# !! vanilla test acount, or comment out the `login' console. +# $Id: test.cf,v 1.2 2003-07-04 11:04:05-07 bryan Exp $ # +default full { + rw *; +} +default * { + logfile /tmp/&; + timestamp ""; + include full; +} +break 5 { + string "\rtest\r"; +} # list of consoles we serve -# name : tty[@host] : baud[parity] : device : group -DOMAINHACK= -LOGDIR=/tmp -BREAK5=\rtest\r -shell:|:9600p:&:5 -bash:|/usr/local/bin/bash::&:2 -web:!www.conserver.com:80:&: -b:/dev/ttyb:9600p:&: -#ts6-10:!ts6:10010:&: -#ts6-11:!ts6:10011:&: -#ts6-12:!ts6:10012:&: -#ts6-13:!ts6:10013:&: -%% +console shell { + master localhost; + timestamp 5; + type exec; + exec ""; +} +console bash { + master localhost; + timestamp 2; + type exec; + exec /usr/local/bin/bash; +} +console web { + master localhost; + type host; + host www.conserver.com; + port 80; +} +console b { + master localhost; + type device; + device /dev/ttyb; + baud 9600; + parity none; +} # list of clients we allow -# type machines -trusted: 127.0.0.1 +access * { + trusted 127.0.0.1; +} diff --git a/conserver.html b/conserver.html index c6fd575..c2b3fb7 100644 --- a/conserver.html +++ b/conserver.html @@ -183,11 +183,11 @@

Downloading

-

The current version, released on Apr 9, 2003, is 7.2.7.tar.gz. You can get it via +

The current version, released on Sep 22, 2003, is 8.0.0.tar.gz. You can get it via FTP - or HTTP. See the FTP + or HTTP. See the CHANGES file for information on the latest updates.

@@ -216,7 +216,7 @@ more), please let me know.

    -
  • AIX 4.3.3/5.1, native cc
  • +
  • AIX 4.3.3/5.1/5.2, native cc
  • BSDI BSD/OS 3.X, gcc
  • @@ -226,7 +226,7 @@
  • DEC Tru64 4.0/5.1, native cc
  • -
  • FreeBSD 4.2 (x86), gcc
  • +
  • FreeBSD 4.2/4.8/5.1 (x86), gcc
  • HP-UX 10.20, gcc
  • diff --git a/conserver/Makefile.in b/conserver/Makefile.in index cc65ced..2a1fb0d 100644 --- a/conserver/Makefile.in +++ b/conserver/Makefile.in @@ -6,6 +6,7 @@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ mandir = @mandir@ +exampledir = $(prefix)/share/examples/conserver ### Installation programs and flags INSTALL = @INSTALL@ @@ -31,7 +32,7 @@ CONSERVER_HDRS = ../config.h $(top_srcdir)/compat.h $(srcdir)/access.h \ $(srcdir)/client.h $(srcdir)/consent.h $(srcdir)/group.h \ $(srcdir)/main.h $(srcdir)/master.h $(srcdir)/readcfg.h \ $(srcdir)/util.h -ALL = conserver +ALL = conserver convert all: $(ALL) @@ -39,6 +40,9 @@ all: $(ALL) conserver: $(CONSERVER_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o conserver $(CONSERVER_OBJS) $(LIBS) +convert: convert.o util.o + $(CC) $(CFLAGS) $(LDFLAGS) -o convert convert.o util.o $(LIBS) + .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< @@ -53,7 +57,7 @@ install: conserver $(INSTALL_PROGRAM) conserver $(DESTDIR)$(sbindir) $(MKDIR) $(DESTDIR)$(mandir)/man8 $(INSTALL) conserver.man $(DESTDIR)$(mandir)/man8/conserver.8 - $(MKDIR) $(DESTDIR)$(sysconfdir) - [ -f $(DESTDIR)$(sysconfdir)/conserver.rc ] || $(INSTALL) conserver.rc $(DESTDIR)$(sysconfdir) + $(MKDIR) $(DESTDIR)$(exampledir) + $(INSTALL) conserver.rc $(DESTDIR)$(exampledir) .PHONY: clean distclean install diff --git a/conserver/access.c b/conserver/access.c index 0bb65ec..8413aa5 100644 --- a/conserver/access.c +++ b/conserver/access.c @@ -1,5 +1,5 @@ /* - * $Id: access.c,v 5.53 2003-04-06 05:31:54-07 bryan Exp $ + * $Id: access.c,v 5.66 2003-08-15 14:24:39-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -34,24 +34,9 @@ * 4. This notice may not be removed or altered. */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include +#include #include #include #include @@ -60,7 +45,6 @@ #include - /* Compare an Internet address (IPv4 expected), with an address pattern * passed as a character string representing an address in the Internet * standard `.' notation, optionally followed by a slash and an integer @@ -84,9 +68,12 @@ AddrCmp(addr, pattern) { in_addr_t hostaddr, pattern_addr, netmask; char *p, *slash_posn; - static STRING *buf = (STRING *) 0; + static STRING *buf = (STRING *)0; +#if HAVE_INET_ATON + struct in_addr inetaddr; +#endif - if (buf == (STRING *) 0) + if (buf == (STRING *)0) buf = AllocString(); slash_posn = strchr(pattern, '/'); if (slash_posn != NULL) { @@ -97,9 +84,15 @@ AddrCmp(addr, pattern) } else p = pattern; +#if HAVE_INET_ATON + if (inet_aton(p, &inetaddr) == 0) + return 1; + pattern_addr = inetaddr.s_addr; +#else pattern_addr = inet_addr(p); if (pattern_addr == (in_addr_t) (-1)) return 1; /* malformed address */ +#endif if (slash_posn) { /* convert explicit netmask */ @@ -123,9 +116,9 @@ AddrCmp(addr, pattern) netmask = 0xffffffff; /* compare entire addresses */ hostaddr = addr->s_addr; - Debug(1, "AddrCmp(): host=%lx(%lx/%lx) acl=%lx(%lx/%lx)", - hostaddr & netmask, hostaddr, netmask, pattern_addr & netmask, - pattern_addr, netmask); + CONDDEBUG((1, "AddrCmp(): host=%lx(%lx/%lx) acl=%lx(%lx/%lx)", + hostaddr & netmask, hostaddr, netmask, + pattern_addr & netmask, pattern_addr, netmask)); return (hostaddr & netmask) != (pattern_addr & netmask); } @@ -133,53 +126,102 @@ AddrCmp(addr, pattern) */ char #if PROTOTYPES -AccType(struct in_addr *addr, char *hname) +AccType(struct in_addr *addr, char **peername) #else -AccType(addr, hname) +AccType(addr, peername) struct in_addr *addr; - char *hname; + char **peername; #endif { - char *pcName; - int len; ACCESS *pACtmp; + socklen_t so; + struct hostent *he = (struct hostent *)0; + int a; +#if TRUST_REVERSE_DNS + char *pcName; + int wlen; + char *hname; + int len; +#endif - if (fDebug) { - if (hname) - Debug(1, "AccType(): hostname=%s, ip=%s", hname, - inet_ntoa(*addr)); - else - Debug(1, "AccType(): hostname=, ip=%s", - inet_ntoa(*addr)); - } - for (pACtmp = pACList; pACtmp != (ACCESS *) 0; - pACtmp = pACtmp->pACnext) { - Debug(1, "AccType(): who=%s, trust=%c", pACtmp->pcwho, - pACtmp->ctrust); + CONDDEBUG((1, "AccType(): ip=%s", inet_ntoa(*addr))); + + so = sizeof(*addr); + for (pACtmp = pACList; pACtmp != (ACCESS *)0; pACtmp = pACtmp->pACnext) { + CONDDEBUG((1, "AccType(): who=%s, trust=%c", pACtmp->pcwho, + pACtmp->ctrust)); if (pACtmp->isCIDR != 0) { - if (0 == AddrCmp(addr, pACtmp->pcwho)) { + if (AddrCmp(addr, pACtmp->pcwho) == 0) return pACtmp->ctrust; - } continue; } - if (hname && hname[0] != '\000') { - pcName = hname; - len = strlen(pcName); - while (len >= pACtmp->ilen) { - Debug(1, "AccType(): name=%s", pcName); - if (0 == strcasecmp(pcName, pACtmp->pcwho)) { + + if ((he = gethostbyname(pACtmp->pcwho)) == (struct hostent *)0) { + Error("AccType(): gethostbyname(%s): %s", pACtmp->pcwho, + hstrerror(h_errno)); + continue; + } + if (4 != he->h_length || AF_INET != he->h_addrtype) { + Error + ("AccType(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)", + pACtmp->pcwho, he->h_length, AF_INET, he->h_addrtype); + continue; + } + for (a = 0; he->h_addr_list[a] != (char *)0; a++) { + CONDDEBUG((1, "AccType(): addr=%s", + inet_ntoa(*(struct in_addr *) + (he->h_addr_list[a])))); + if ( +#if HAVE_MEMCMP + memcmp(&(addr->s_addr), he->h_addr_list[a], + he->h_length) +#else + bcmp(&(addr->s_addr), he->h_addr_list[a], he->h_length) +#endif + == 0) + return pACtmp->ctrust; + } + } + +#if TRUST_REVERSE_DNS + /* if we trust reverse dns, we get the names associated with + * the address we're checking and then check each of those + * against the access list entries. + * we chop bits off client names so that we can put domain + * names in access lists or even top-level domains. + * allowed conserver.com, net; + * this allows anything from conserver.com and anything in + * the .net top-level. without TRUST_REVERSE_DNS, those names + * better map to ip addresses for them to take effect. + */ + if ((he = + gethostbyaddr((char *)addr, so, + AF_INET)) == (struct hostent *)0) { + Error("AccType(): gethostbyaddr(%s): %s", inet_ntoa(*addr), + hstrerror(h_errno)); + return config->defaultaccess; + } + for (pACtmp = pACList; pACtmp != (ACCESS *)0; pACtmp = pACtmp->pACnext) { + if (pACtmp->isCIDR != 0) + continue; + wlen = strlen(pACtmp->pcwho); + for (hname = he->h_name, a = 0; hname != (char *)0; + hname = he->h_aliases[a++]) { + for (pcName = hname, len = strlen(pcName); len >= wlen; + len = strlen(++pcName)) { + CONDDEBUG((1, "AccType(): name=%s", pcName)); + if (strcasecmp(pcName, pACtmp->pcwho) == 0) { + *peername = hname; return pACtmp->ctrust; } pcName = strchr(pcName, '.'); - if ((char *)0 == pcName) { + if (pcName == (char *)0) break; - } - ++pcName; - len = strlen(pcName); } } } - return chDefAcc; +#endif + return config->defaultaccess; } void @@ -191,100 +233,51 @@ SetDefAccess(pAddr, pHost) char *pHost; #endif { - char *pcWho, *pcDomain; - int iLen; + char *pcDomain; char *addr; + ACCESS *a; - addr = inet_ntoa(*pAddr); - iLen = strlen(addr); - if ((ACCESS *) 0 == (pACList = (ACCESS *) calloc(1, sizeof(ACCESS)))) { - OutOfMem(); + while (pAddr->s_addr != (in_addr_t) 0) { + addr = inet_ntoa(*pAddr); + if ((a = (ACCESS *)calloc(1, sizeof(ACCESS))) == (ACCESS *)0) + OutOfMem(); + if ((a->pcwho = strdup(addr)) == (char *)0) + OutOfMem(); + a->ctrust = 'a'; + a->pACnext = pACList; + pACList = a; + + CONDDEBUG((1, "SetDefAccess(): trust=%c, who=%s", pACList->ctrust, + pACList->pcwho)); + pAddr++; } - if ((char *)0 == (pcWho = malloc(iLen + 1))) { - OutOfMem(); - } - pACList->ctrust = 'a'; - pACList->ilen = iLen; - pACList->pcwho = strcpy(pcWho, addr); - Debug(1, "SetDefAccess(): trust=%c, who=%s", pACList->ctrust, - pACList->pcwho); - - if ((char *)0 == (pcDomain = strchr(pHost, '.'))) { + if ((char *)0 == (pcDomain = strchr(pHost, '.'))) return; - } ++pcDomain; - iLen = strlen(pcDomain); - if ((ACCESS *) 0 == - (pACList->pACnext = (ACCESS *) calloc(1, sizeof(ACCESS)))) { + if ((a = (ACCESS *)calloc(1, sizeof(ACCESS))) == (ACCESS *)0) OutOfMem(); - } - if ((char *)0 == (pcWho = malloc(iLen + 1))) { + if ((a->pcwho = strdup(pcDomain)) == (char *)0) OutOfMem(); - } - pACList->pACnext->ctrust = 'a'; - pACList->pACnext->ilen = iLen; - pACList->pACnext->pcwho = strcpy(pcWho, pcDomain); + a->ctrust = 'a'; + a->pACnext = pACList; + pACList = a; - Debug(1, "SetDefAccess(): trust=%c, who=%s", pACList->pACnext->ctrust, - pACList->pACnext->pcwho); -} - -/* thread ther list of uniq console server machines, aliases for (ksb) - * machines will screw us up - */ -REMOTE * -#if PROTOTYPES -FindUniq(REMOTE * pRCAll) -#else -FindUniq(pRCAll) - REMOTE *pRCAll; -#endif -{ - REMOTE *pRC; - - /* INV: tail of the list we are building always contains only - * uniq hosts, or the empty list. - */ - if ((REMOTE *) 0 == pRCAll) { - return (REMOTE *) 0; - } - - pRCAll->pRCuniq = FindUniq(pRCAll->pRCnext); - - /* if it is in the returned list of uniq hosts, return that list - * else add us by returning our node - */ - for (pRC = pRCAll->pRCuniq; (REMOTE *) 0 != pRC; pRC = pRC->pRCuniq) { - if (0 == strcasecmp(pRC->rhost.string, pRCAll->rhost.string)) { - return pRCAll->pRCuniq; - } - } - return pRCAll; + CONDDEBUG((1, "SetDefAccess(): trust=%c, who=%s", pACList->ctrust, + pACList->pcwho)); } void #if PROTOTYPES -DestroyRemoteConsole(REMOTE * pRCList) -#else -DestroyRemoteConsole(pRCList) - REMOTE *pRCList; -#endif -{ - DestroyString(&pRCList->rserver); - DestroyString(&pRCList->rhost); - free(pRCList); -} - -void -#if PROTOTYPES -DestroyAccessList(ACCESS * pACList) +DestroyAccessList(ACCESS *pACList) #else DestroyAccessList(pACList) ACCESS *pACList; #endif { + if (pACList == (ACCESS *)0) + return; if (pACList->pcwho != (char *)0) free(pACList->pcwho); free(pACList); diff --git a/conserver/access.h b/conserver/access.h index 2464c73..ea65bf9 100644 --- a/conserver/access.h +++ b/conserver/access.h @@ -1,5 +1,5 @@ /* - * $Id: access.h,v 5.22 2003-03-06 10:13:41-08 bryan Exp $ + * $Id: access.h,v 5.26 2003-08-10 11:11:20-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -39,21 +39,11 @@ typedef struct access { char ctrust; /* how much do we trust the host */ - int ilen; /* length (strlen) of pcwho */ char *pcwho; /* what is the hosts name/ip number */ int isCIDR; /* is this a CIDR addr (or hostname?) */ struct access *pACnext; /* next access list */ } ACCESS; -typedef struct remote { /* console at another host */ - struct remote *pRCnext; /* next remote console we know about */ - struct remote *pRCuniq; /* list of uniq remote servers */ - STRING rserver; /* remote server name */ - STRING rhost; /* remote host to call to get it */ -} REMOTE; - -extern REMOTE *FindUniq PARAMS((REMOTE *)); -extern char AccType PARAMS((struct in_addr *, char *)); +extern char AccType PARAMS((struct in_addr *, char **)); extern void SetDefAccess PARAMS((struct in_addr *, char *)); -extern void DestroyRemoteConsole PARAMS((REMOTE *)); extern void DestroyAccessList PARAMS((ACCESS *)); diff --git a/conserver/client.c b/conserver/client.c index d1f7839..7fed7eb 100644 --- a/conserver/client.c +++ b/conserver/client.c @@ -1,5 +1,5 @@ /* - * $Id: client.c,v 5.60 2003-03-17 08:38:40-08 bryan Exp $ + * $Id: client.c,v 5.69 2003-08-15 14:24:39-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -34,33 +34,27 @@ * 4. This notice may not be removed or altered. */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include +#include #include +#include #include #include +#if defined(USE_LIBWRAP) +#include +#include +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif + /* find the next guy who wants to write on the console (ksb) */ CONSCLIENT * #if PROTOTYPES -FindWrite(CONSCLIENT * pCL) +FindWrite(CONSCLIENT *pCL) #else FindWrite(pCL) CONSCLIENT *pCL; @@ -71,10 +65,11 @@ FindWrite(pCL) * most recent or some such... I guess it doesn't matter that * much. */ - for ( /*passed in */ ; (CONSCLIENT *) 0 != pCL; pCL = pCL->pCLnext) { - if (!pCL->fwantwr) + for ( /*passed in */ ; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLnext) { + if (!pCL->fwantwr || pCL->fro) continue; - if (!pCL->pCEto->fup || pCL->pCEto->fronly) + if (!(pCL->pCEto->fup && pCL->pCEto->ioState == ISNORMAL) || + pCL->pCEto->fronly) break; pCL->fwantwr = 0; pCL->fwr = 1; @@ -83,10 +78,10 @@ FindWrite(pCL) } else { FileWrite(pCL->fd, "\r\n[attached]\r\n", -1); } - TagLogfileAct(pCL->pCEto, "%s attached", pCL->acid.string); + TagLogfileAct(pCL->pCEto, "%s attached", pCL->acid->string); return pCL; } - return (CONSCLIENT *) 0; + return (CONSCLIENT *)0; } /* replay last iBack lines of the log file upon connect to console (ksb) @@ -97,7 +92,7 @@ FindWrite(pCL) */ void #if PROTOTYPES -Replay(CONSFILE * fdLog, CONSFILE * fdOut, int iBack) +Replay(CONSFILE *fdLog, CONSFILE *fdOut, int iBack) #else Replay(fdLog, fdOut, iBack) CONSFILE *fdLog; @@ -116,8 +111,8 @@ Replay(fdLog, fdOut, iBack) struct stat stLog; struct lines { int is_mark; - STRING line; - STRING mark_end; + STRING *line; + STRING *mark_end; } *lines; int n_lines; int ln; @@ -130,7 +125,7 @@ Replay(fdLog, fdOut, iBack) unsigned long dmallocMarkReplay = 0; #endif - if ((CONSFILE *) 0 == fdLog) { + if ((CONSFILE *)0 == fdLog) { FileWrite(fdOut, "[no log file on this console]\r\n", -1); return; } @@ -160,6 +155,10 @@ Replay(fdLog, fdOut, iBack) if ((struct lines *)0 == lines) { OutOfMem(); } + for (i = 0; i < n_lines; i++) { + lines[i].mark_end = AllocString(); + lines[i].line = AllocString(); + } ln = -1; /* loop as long as there is data in the file or we have not found @@ -185,7 +184,7 @@ Replay(fdLog, fdOut, iBack) goto common_exit; } #endif - if ((r = FileRead(fdLog, buf, BUFSIZ)) <= 0) { + if ((r = FileRead(fdLog, buf, BUFSIZ)) < 0) { goto common_exit; } bp = buf + r; @@ -199,21 +198,21 @@ Replay(fdLog, fdOut, iBack) /* reverse the text to put it in forward order */ - u = lines[ln].line.used - 1; + u = lines[ln].line->used - 1; for (i = 0; i < u / 2; i++) { int temp; - temp = lines[ln].line.string[i]; - lines[ln].line.string[i] - = lines[ln].line.string[u - i - 1]; - lines[ln].line.string[u - i - 1] = temp; + temp = lines[ln].line->string[i]; + lines[ln].line->string[i] + = lines[ln].line->string[u - i - 1]; + lines[ln].line->string[u - i - 1] = temp; } /* see if this line is a MARK */ - if (lines[ln].line.used > 0 && - lines[ln].line.string[0] == '[') { - i = sscanf(lines[ln].line.string + 1, + if (lines[ln].line->used > 0 && + lines[ln].line->string[0] == '[') { + i = sscanf(lines[ln].line->string + 1, "-- MARK -- %3c %3c %d %d:%d:%d %d]\r\n", dummy, dummy, &j, &j, &j, &j, &j); is_mark = (i == 7); @@ -227,27 +226,23 @@ Replay(fdLog, fdOut, iBack) /* this is a mark and the previous line is also * a mark, so make (or continue) that range */ - if (0 == lines[ln - 1].mark_end.allocated) { + if (0 == lines[ln - 1].mark_end->allocated) { /* this is a new range - shuffle pointers * * remember that we are moving backward */ - lines[ln - 1].mark_end = lines[ln - 1].line; - lines[ln - 1].line.string = (char *)0; - lines[ln - 1].line.used = 0; - lines[ln - 1].line.allocated = 0; + *(lines[ln - 1].mark_end) = *(lines[ln - 1].line); + InitString(lines[ln - 1].line); } /* if unallocated, cheat and shuffle pointers */ - if (0 == lines[ln - 1].line.allocated) { - lines[ln - 1].line = lines[ln].line; - lines[ln].line.string = (char *)0; - lines[ln].line.used = 0; - lines[ln].line.allocated = 0; + if (0 == lines[ln - 1].line->allocated) { + *(lines[ln - 1].line) = *(lines[ln].line); + InitString(lines[ln].line); } else { - BuildString((char *)0, &lines[ln - 1].line); - BuildString(lines[ln].line.string, - &lines[ln - 1].line); - BuildString((char *)0, &lines[ln].line); + BuildString((char *)0, lines[ln - 1].line); + BuildString(lines[ln].line->string, + lines[ln - 1].line); + BuildString((char *)0, lines[ln].line); } ln--; } @@ -268,14 +263,14 @@ Replay(fdLog, fdOut, iBack) if (ln < 0) { ln = 0; } - BuildStringChar(ch, &lines[ln].line); + BuildStringChar(ch, lines[ln].line); /* if we've processed "a lot" of data for a line, then bail * why? there must be some very long non-newline terminated * strings and if we just keep going back, we could spew lots * of data and chew up lots of memory */ - if (lines[ln].line.used > MAXREPLAYLINELEN) { + if (lines[ln].line->used > MAXREPLAYLINELEN) { break; } } @@ -284,18 +279,18 @@ Replay(fdLog, fdOut, iBack) /* if we got back to beginning of file but saw some data, include it */ - if (ln >= 0 && lines[ln].line.used > 0) { + if (ln >= 0 && lines[ln].line->used > 0) { /* reverse the text to put it in forward order */ - u = lines[ln].line.used - 1; + u = lines[ln].line->used - 1; for (i = 0; i < u / 2; i++) { int temp; - temp = lines[ln].line.string[i]; - lines[ln].line.string[i] - = lines[ln].line.string[u - i - 1]; - lines[ln].line.string[u - i - 1] = temp; + temp = lines[ln].line->string[i]; + lines[ln].line->string[i] + = lines[ln].line->string[u - i - 1]; + lines[ln].line->string[u - i - 1] = temp; } ln++; } @@ -303,16 +298,16 @@ Replay(fdLog, fdOut, iBack) /* copy the lines into the buffer and put them in order */ for (i = ln - 1; i >= 0; i--) { - if (lines[i].is_mark && 0 != lines[i].mark_end.used) { + if (lines[i].is_mark && 0 != lines[i].mark_end->used) { int mark_len; /* output the start of the range, stopping at the ']' */ - s = strrchr(lines[i].line.string, ']'); + s = strrchr(lines[i].line->string, ']'); if ((char *)0 != s) { *s = '\000'; } - FileWrite(fdOut, lines[i].line.string, -1); + FileWrite(fdOut, lines[i].line->string, -1); FileWrite(fdOut, " .. ", -1); /* build the end string by removing the leading "[-- MARK -- " @@ -320,24 +315,24 @@ Replay(fdLog, fdOut, iBack) */ mark_len = sizeof("[-- MARK -- ") - 1; - s = strrchr(lines[i].mark_end.string + mark_len, ']'); + s = strrchr(lines[i].mark_end->string + mark_len, ']'); if ((char *)0 != s) { *s = '\000'; } - FileWrite(fdOut, lines[i].mark_end.string + mark_len, -1); + FileWrite(fdOut, lines[i].mark_end->string + mark_len, -1); FileWrite(fdOut, " -- MARK --]\r\n", -1); - u = lines[i].mark_end.used; - s = lines[i].mark_end.string; + u = lines[i].mark_end->used; + s = lines[i].mark_end->string; } else - FileWrite(fdOut, lines[i].line.string, -1); + FileWrite(fdOut, lines[i].line->string, -1); } common_exit: if ((struct lines *)0 != lines) { for (i = 0; i < n_lines; i++) { - DestroyString(&lines[i].mark_end); - DestroyString(&lines[i].line); + DestroyString(lines[i].mark_end); + DestroyString(lines[i].line); } free(lines); lines = (struct lines *)0; @@ -347,7 +342,7 @@ Replay(fdLog, fdOut, iBack) buf = (char *)0; } #if HAVE_DMALLOC && DMALLOC_MARK_REPLAY - Debug(1, "Replay(): dmalloc / MarkReplay"); + CONDDEBUG((1, "Replay(): dmalloc / MarkReplay")); dmalloc_log_changed(dmallocMarkReplay, 1, 0, 1); #endif } @@ -408,7 +403,7 @@ static HELP aHLTable[] = { */ void #if PROTOTYPES -HelpUser(CONSCLIENT * pCL) +HelpUser(CONSCLIENT *pCL) #else HelpUser(pCL) CONSCLIENT *pCL; @@ -418,9 +413,9 @@ HelpUser(pCL) static char acH1[] = "help]\r\n", acH2[] = "help spy mode]\r\n", acEoln[] = "\r\n"; - static STRING *acLine = (STRING *) 0; + static STRING *acLine = (STRING *)0; - if (acLine == (STRING *) 0) + if (acLine == (STRING *)0) acLine = AllocString(); iCmp = WHEN_ALWAYS | WHEN_SPY; @@ -470,3 +465,59 @@ HelpUser(pCL) FileWrite(pCL->fd, acLine->string, -1); } } + +int +#if PROTOTYPES +ClientAccessOk(CONSCLIENT *pCL) +#else +ClientAccessOk(pCL) + CONSCLIENT *pCL; +#endif +{ + char *peername = (char *)0; + socklen_t so; + int cfd; + struct sockaddr_in in_port; + int retval = 1; + int getpeer = -1; + + cfd = FileFDNum(pCL->fd); + pCL->caccess = 'r'; +#if defined(USE_LIBWRAP) + { + struct request_info request; + request_init(&request, RQ_DAEMON, progname, RQ_FILE, cfd, 0); + fromhost(&request); + if (!hosts_access(&request)) { + FileWrite(pCL->fd, "access from your host refused\r\n", -1); + retval = 0; + goto setpeer; + } + } +#endif + + so = sizeof(in_port); + if (-1 == + (getpeer = getpeername(cfd, (struct sockaddr *)&in_port, &so))) { + FileWrite(pCL->fd, "getpeername failed\r\n", -1); + retval = 0; + goto setpeer; + } + pCL->caccess = AccType(&in_port.sin_addr, &peername); + if (pCL->caccess == 'r') { + FileWrite(pCL->fd, "access from your host refused\r\n", -1); + retval = 0; + } + + setpeer: + if (pCL->peername != (STRING *)0) { + BuildString((char *)0, pCL->peername); + if (peername != (char *)0) + BuildString(peername, pCL->peername); + else if (getpeer != -1) + BuildString(inet_ntoa(in_port.sin_addr), pCL->peername); + else + BuildString("", pCL->peername); + } + return retval; +} diff --git a/conserver/client.h b/conserver/client.h index 94777ea..83f8ba3 100644 --- a/conserver/client.h +++ b/conserver/client.h @@ -1,5 +1,5 @@ /* - * $Id: client.h,v 5.27 2003-03-06 10:13:41-08 bryan Exp $ + * $Id: client.h,v 5.31 2003-08-24 13:00:50-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -35,27 +35,30 @@ */ /* states for a server fsm */ -#define S_NORMAL 0 /* just pass character */ -#define S_ESC1 1 /* first escape character received */ -#define S_CMD 2 /* second interrupt character received */ -#define S_CATTN 3 /* change 1 escape character to next input char */ -#define S_CESC 4 /* change 2 escape character to next input char */ -#define S_HALT1 5 /* we have a halt sequence in progress */ -#define S_SUSP 6 /* we are suspened, first char wakes us up */ -#define S_IDENT 7 /* probational connection (who is this) */ -#define S_HOST 8 /* still needs a host name to connect */ -#define S_PASSWD 9 /* still needs a passwd to connect */ -#define S_QUOTE 10 /* send any character we can spell */ -#define S_BCAST 11 /* send a broadcast message to all connections */ +typedef enum clientState { + S_NORMAL, /* just pass character */ + S_ESC1, /* first escape character received */ + S_CMD, /* second interrupt character received */ + S_CATTN, /* change 1 escape char to next input char */ + S_CESC, /* change 2 escape char to next input char */ + S_HALT1, /* we have a halt sequence in progress */ + S_SUSP, /* we are suspened, first char wakes us up */ + S_IDENT, /* probational connection (who is this) */ + S_PASSWD, /* still needs a passwd to connect */ + S_QUOTE, /* send any character we can spell */ + S_BCAST /* send a broadcast message to all clients */ +} CLIENTSTATE; typedef struct client { /* Connection Information: */ CONSFILE *fd; /* file descriptor */ short fcon; /* currently connect or not */ short fwr; /* (client) write enable flag */ short fwantwr; /* (client) wants to write */ + short fro; /* read-only permission */ short fecho; /* echo commands (not set by machines) */ - STRING acid; /* login and location of client */ - STRING peername; /* location of client */ + STRING *acid; /* login and location of client */ + STRING *peername; /* location of client */ + STRING *username; /* login of client */ time_t tym; /* time of connect */ time_t typetym; /* time of last keystroke */ char actym[32]; /* pre-formatted time */ @@ -70,10 +73,12 @@ typedef struct client { /* Connection Information: */ *pCLnext; /* next person on this list */ /* next lists link clients on a console */ char ic[2]; /* two character escape sequence */ - char iState; /* state for fsm in server */ + CLIENTSTATE iState; /* state for fsm in server */ char caccess; /* did we trust the remote machine */ - STRING accmd; /* the command the user issued */ - STRING msg; /* the broadcast message */ + IOSTATE ioState; /* state of the socket */ + time_t stateTimer; /* timer for various ioState states */ + STRING *accmd; /* the command the user issued */ + STRING *msg; /* the broadcast message */ struct sockaddr_in cnct_port; /* where from */ } CONSCLIENT; @@ -81,3 +86,4 @@ typedef struct client { /* Connection Information: */ extern void Replay PARAMS((CONSFILE *, CONSFILE *, int)); extern void HelpUser PARAMS((CONSCLIENT *)); extern CONSCLIENT *FindWrite PARAMS((CONSCLIENT *)); +extern int ClientAccessOk PARAMS((CONSCLIENT *)); diff --git a/conserver/consent.c b/conserver/consent.c index 5e07085..aacc626 100644 --- a/conserver/consent.c +++ b/conserver/consent.c @@ -1,5 +1,5 @@ /* - * $Id: consent.c,v 5.103 2003-04-06 05:32:20-07 bryan Exp $ + * $Id: consent.c,v 5.125 2003-08-15 14:24:39-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -38,35 +38,20 @@ * Network console modifications by Robert Olson, olson@mcs.anl.gov. */ -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include - #include #include #include +#include +#include #include -struct hostcache *hostcachelist = NULL; - BAUD baud[] = { - {"Netwk", 0}, - {"Local", 0}, #if defined(B115200) {"115200", B115200}, #endif @@ -79,9 +64,15 @@ BAUD baud[] = { #if defined(B19200) {"19200", B19200}, #endif +#if defined(B9600) {"9600", B9600}, +#endif +#if defined(B4800) {"4800", B4800}, +#endif +#if defined(B2400) {"2400", B2400}, +#endif #if defined(B1800) {"1800", B1800}, #endif @@ -89,6 +80,9 @@ BAUD baud[] = { #if defined(B600) {"600", B600}, #endif +#if defined(B300) + {"300", B300}, +#endif }; @@ -105,51 +99,25 @@ FindBaud(pcMode) int i; for (i = 0; i < sizeof(baud) / sizeof(struct baud); ++i) { - if (0 != strncmp(pcMode, baud[i].acrate, strlen(baud[i].acrate))) - continue; - return baud + i; + if (strcmp(pcMode, baud[i].acrate) == 0) + return baud + i; } - return baud; + return (BAUD *)0; } -PARITY parity[] = { -#if HAVE_TERMIOS_H - {' ', 0, 0} - , /* Blank for network */ # if !defined(PAREXT) # define PAREXT 0 # endif - {'e', PARENB | CS7, 0} - , /* even */ - {'m', PARENB | CS7 | PARODD | PAREXT, 0} - , /* mark */ - {'n', CS8, 0} - , /* pass 8 bits, no parity */ - {'o', PARENB | CS7 | PARODD, 0} - , /* odd */ - {'p', CS8, 0} - , /* pass 8 bits, no parity */ - {'s', PARENB | CS7 | PAREXT, 0} - , /* space */ -#else /* ! HAVE_TERMIOS_H */ - {'e', EVENP, ODDP} - , /* even */ - {'m', EVENP | ODDP, 0} - , /* mark */ - {'o', ODDP, EVENP} - , /* odd */ -# if defined(PASS8) - {'n', PASS8, EVENP | ODDP} - , /* pass 8 bits, no parity */ - {'p', PASS8, EVENP | ODDP} - , /* pass 8 bits, no parity */ -# endif - {'s', 0, EVENP | ODDP} /* space */ -#endif +struct parity parity[] = { + {"even", PARENB | CS7, 0}, + {"mark", PARENB | CS7 | PARODD | PAREXT, 0}, + {"none", CS8, 0}, + {"odd", PARENB | CS7 | PARODD, 0}, + {"space", PARENB | CS7 | PAREXT, 0}, }; -/* find a parity on the end of a baud "9600even" -> EVEN (ksb) +/* find a parity "even" or "E" or "ev" -> EVEN */ PARITY * #if PROTOTYPES @@ -160,44 +128,37 @@ FindParity(pcMode) #endif { int i; - char acFirst; - while (isdigit((int)(*pcMode))) { - ++pcMode; - } - acFirst = *pcMode; - if (isupper((int)(acFirst))) - acFirst = tolower(acFirst); for (i = 0; i < sizeof(parity) / sizeof(struct parity); ++i) { - if (acFirst != parity[i].ckey) - continue; - return parity + i; + if (strcasecmp(pcMode, parity[i].key) == 0) + return parity + i; } - return parity; + return (PARITY *)0; } -#if HAVE_TERMIOS_H /* setup a tty device (ksb) */ static int #if PROTOTYPES -TtyDev(CONSENT * pCE, fd_set * pfdSet) +TtyDev(CONSENT *pCE) #else -TtyDev(pCE, pfdSet) +TtyDev(pCE) CONSENT *pCE; - fd_set *pfdSet; #endif { struct termios termp; struct stat stPerm; + int cofile; + + cofile = FileFDNum(pCE->cofile); /* here we should fstat for `read-only' checks */ - if (-1 == fstat(pCE->fdtty, &stPerm)) { - Error("[%s] fstat(%s(%d)): %s: forcing down", pCE->server.string, - pCE->dfile.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if (-1 == fstat(cofile, &stPerm)) { + Error("[%s] fstat(%s(%d)): %s: forcing down", pCE->server, + pCE->device, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return -1; } else if (0 == (stPerm.st_mode & 0222)) { /* any device that is read-only we won't write to @@ -208,11 +169,10 @@ TtyDev(pCE, pfdSet) /* * Get terminal attributes */ - if (-1 == tcgetattr(pCE->fdtty, &termp)) { - Error("[%s] tcgetattr(%s(%d)): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if (-1 == tcgetattr(cofile, &termp)) { + Error("[%s] tcgetattr(%s(%d)): %s: forcing down", pCE->server, + pCE->device, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return -1; } @@ -224,13 +184,27 @@ TtyDev(pCE, pfdSet) * isig No signal generation * Turn on: ixoff */ - termp.c_iflag = IXON | IXOFF | BRKINT; + termp.c_iflag = BRKINT; + if (pCE->ixon == FLAGTRUE) + termp.c_iflag |= IXON; + if (pCE->ixany == FLAGTRUE) + termp.c_iflag |= IXANY; + if (pCE->ixoff == FLAGTRUE) + termp.c_iflag |= IXOFF; termp.c_oflag = 0; /* CLOCAL suggested by egan@us.ibm.com * carrier transitions result in dropped consoles otherwise */ termp.c_cflag = CREAD | CLOCAL; - termp.c_cflag |= pCE->pparity->iset; + if (pCE->hupcl == FLAGTRUE) + termp.c_cflag |= HUPCL; + if (pCE->cstopb == FLAGTRUE) + termp.c_cflag |= CSTOPB; +#if defined(CRTSCTS) + if (pCE->crtscts == FLAGTRUE) + termp.c_cflag |= CRTSCTS; +#endif + termp.c_cflag |= pCE->parity->iset; termp.c_lflag = 0; /* * Set the VMIN == 1 @@ -240,184 +214,51 @@ TtyDev(pCE, pfdSet) termp.c_cc[VMIN] = 1; termp.c_cc[VTIME] = 1; - if (-1 == cfsetospeed(&termp, pCE->pbaud->irate)) { - Error("[%s] cfsetospeed(%s(%d)): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if (-1 == cfsetospeed(&termp, pCE->baud->irate)) { + Error("[%s] cfsetospeed(%s(%d)): %s: forcing down", pCE->server, + pCE->device, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return -1; } - if (-1 == cfsetispeed(&termp, pCE->pbaud->irate)) { - Error("[%s] cfsetispeed(%s(%d)): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if (-1 == cfsetispeed(&termp, pCE->baud->irate)) { + Error("[%s] cfsetispeed(%s(%d)): %s: forcing down", pCE->server, + pCE->device, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return -1; } /* * Set terminal attributes */ - if (-1 == tcsetattr(pCE->fdtty, TCSADRAIN, &termp)) { + if (-1 == tcsetattr(cofile, TCSADRAIN, &termp)) { Error("[%s] tcsetattr(%s(%d),TCSADRAIN): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); + pCE->server, pCE->device, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return -1; } # if HAVE_STROPTS_H /* * eat all the streams modules upto and including ttcompat */ - while (ioctl(pCE->fdtty, I_FIND, "ttcompat") == 1) { - ioctl(pCE->fdtty, I_POP, 0); + while (ioctl(cofile, I_FIND, "ttcompat") == 1) { + ioctl(cofile, I_POP, 0); } # endif pCE->fup = 1; return 0; } -#else /* ! HAVE_TERMIOS_H */ - -# if HAVE_SGTTY_H - -/* setup a tty device (ksb) - */ -static int -#if PROTOTYPES -TtyDev(CONSENT * pCE, fd_set * pfdSet) -#else -TtyDev(pCE) - CONSENT *pCE; - fd_set *pfdSet; -#endif -{ - struct sgttyb sty; - struct tchars m_tchars; - struct ltchars m_ltchars; - struct stat stPerm; - - /* here we should fstat for `read-only' checks - */ - if (-1 == fstat(pCE->fdtty, &stPerm)) { - Error("[%s] fstat(%s(%d)): %s: forcing down", pCE->server.string, - pCE->dfile.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } else if (0 == (stPerm.st_mode & 0222)) { - /* any device that is read-only we won't write to - */ - pCE->fronly = 1; - } -# if defined(TIOCSSOFTCAR) - if (-1 == ioctl(pCE->fdtty, TIOCSSOFTCAR, &fSoftcar)) { - Error("[%s] ioctl(%s(%d),TIOCSSOFTCAR): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } -# endif - - /* stty 9600 raw cs7 - */ - if (-1 == ioctl(pCE->fdtty, TIOCGETP, (char *)&sty)) { - Error("[%s] ioctl(%s(%d),TIOCGETP): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } - sty.sg_flags &= ~(ECHO | CRMOD | pCE->pparity->iclr); - sty.sg_flags |= (CBREAK | TANDEM | pCE->pparity->iset); - sty.sg_erase = -1; - sty.sg_kill = -1; - sty.sg_ispeed = pCE->pbaud->irate; - sty.sg_ospeed = pCE->pbaud->irate; - if (-1 == ioctl(pCE->fdtty, TIOCSETP, (char *)&sty)) { - Error("[%s] ioctl(%s(%d),TIOCSETP): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } - - /* stty undef all tty chars - * (in cbreak mode we may not need to this... but we do) - */ - if (-1 == ioctl(pCE->fdtty, TIOCGETC, (char *)&m_tchars)) { - Error("[%s] ioctl(%s(%d),TIOCGETC): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } - m_tchars.t_intrc = -1; - m_tchars.t_quitc = -1; - m_tchars.t_startc = -1; - m_tchars.t_stopc = -1; - m_tchars.t_eofc = -1; - m_tchars.t_brkc = -1; - if (-1 == ioctl(pCE->fdtty, TIOCSETC, (char *)&m_tchars)) { - Error("[%s] ioctl(%s(%d),TIOCSETC): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } - if (-1 == ioctl(pCE->fdtty, TIOCGLTC, (char *)&m_ltchars)) { - Error("[%s] ioctl(%s(%d),TIOCGLTC): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } - m_ltchars.t_werasc = -1; - m_ltchars.t_flushc = -1; - m_ltchars.t_lnextc = -1; - m_ltchars.t_suspc = -1; - m_ltchars.t_dsuspc = -1; - if (-1 == ioctl(pCE->fdtty, TIOCSLTC, (char *)&m_ltchars)) { - Error("[%s] ioctl(%s(%d),TIOCSLTC): %s: forcing down", - pCE->server.string, pCE->dfile.string, pCE->fdtty, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return -1; - } -# if HAVE_STROPTS_H - /* pop off the un-needed streams modules (on a sun3 machine esp.) - * (Idea by jrs@ecn.purdue.edu) - */ - while (ioctl(pCE->fdtty, I_POP, 0) == 0) { - /* eat all the streams modules */ ; - } -# endif - pCE->fup = 1; - return 0; -} -# endif /* HAVE_SGTTY_H */ - -#endif /* HAVE_TERMIOS_H */ - /* setup a virtual device (ksb) */ static int #if PROTOTYPES -VirtDev(CONSENT * pCE) +VirtDev(CONSENT *pCE) #else VirtDev(pCE) CONSENT *pCE; #endif { -# if HAVE_TERMIOS_H static struct termios n_tio; -# else -# if HAVE_SGTTY_H - struct sgttyb sty; - struct tchars m_tchars; - struct ltchars m_ltchars; -# endif -# endif int i; pid_t iNewGrp; extern char **environ; @@ -428,13 +269,12 @@ VirtDev(pCE) switch (pCE->ipid = fork()) { case -1: + pCE->ipid = 0; return -1; case 0: thepid = getpid(); break; default: - Verbose("[%s] pid %lu on %s", pCE->server.string, pCE->ipid, - pCE->acslave.string); fflush(stderr); pCE->fup = 1; return 0; @@ -462,7 +302,8 @@ VirtDev(pCE) */ i = GetMaxFiles(); for ( /* i above */ ; --i > 2;) { - close(i); + if (i != pCE->execSlaveFD) + close(i); } /* leave 2 until we *have to close it* */ @@ -472,15 +313,15 @@ VirtDev(pCE) # if HAVE_SETSID iNewGrp = setsid(); if (-1 == iNewGrp) { - Error("[%s] setsid(): %s", pCE->server.string, strerror(errno)); + Error("[%s] setsid(): %s", pCE->server, strerror(errno)); iNewGrp = getpid(); } # else iNewGrp = getpid(); # endif - if (0 != open(pCE->acslave.string, O_RDWR, 0) || 1 != dup(0)) { - Error("[%s] fd sync error", pCE->server.string); + if (dup(pCE->execSlaveFD) != 0 || dup(pCE->execSlaveFD) != 1) { + Error("[%s] fd sync error", pCE->server); Bye(EX_OSERR); } # if HAVE_STROPTS_H && !defined(_AIX) @@ -488,28 +329,27 @@ VirtDev(pCE) * under PTX (others?) we have to push the compatibility * streams modules `ptem', `ld', and `ttcompat' */ - Debug(1, "VirtDev(): pushing ptemp onto pseudo-terminal"); + CONDDEBUG((1, "VirtDev(): pushing ptemp onto pseudo-terminal")); ioctl(0, I_PUSH, "ptem"); - Debug(1, "VirtDev(): pushing ldterm onto pseudo-terminal"); + CONDDEBUG((1, "VirtDev(): pushing ldterm onto pseudo-terminal")); ioctl(0, I_PUSH, "ldterm"); - Debug(1, "VirtDev(): pushing ttcompat onto pseudo-terminal"); + CONDDEBUG((1, "VirtDev(): pushing ttcompat onto pseudo-terminal")); ioctl(0, I_PUSH, "ttcompat"); - Debug(1, "VirtDev(): done pushing modules onto pseudo-terminal"); + CONDDEBUG((1, "VirtDev(): done pushing modules onto pseudo-terminal")); # endif -# if HAVE_TERMIOS_H -# if HAVE_TCGETATTR - if (0 != tcgetattr(0, &n_tio)) -# else - if (0 != ioctl(0, TCGETS, &n_tio)) -# endif - { - Error("[%s] ioctl(0,TCGETS): %s", pCE->server.string, - strerror(errno)); + if (0 != tcgetattr(0, &n_tio)) { + Error("[%s] tcgetattr(0): %s", pCE->server, strerror(errno)); Bye(EX_OSERR); } n_tio.c_iflag &= ~(IGNCR | IUCLC); - n_tio.c_iflag |= ICRNL | IXON | IXANY; + n_tio.c_iflag |= ICRNL; + if (pCE->ixon == FLAGTRUE) + n_tio.c_iflag |= IXON; + if (pCE->ixany == FLAGTRUE) + n_tio.c_iflag |= IXANY; + if (pCE->ixoff == FLAGTRUE) + n_tio.c_iflag |= IXOFF; n_tio.c_oflag &= ~(OLCUC | ONOCR | ONLRET | OFILL | NLDLY | CRDLY | TABDLY | BSDLY); n_tio.c_oflag |= OPOST | ONLCR; @@ -525,93 +365,19 @@ VirtDev(pCE) n_tio.c_cc[VSTART] = '\021'; n_tio.c_cc[VSTOP] = '\023'; n_tio.c_cc[VSUSP] = '\032'; -# if HAVE_TCSETATTR - if (0 != tcsetattr(0, TCSANOW, &n_tio)) -# else - if (0 != ioctl(0, TCSETS, &n_tio)) -# endif - { - Error("[%s] ioctl(0,TCSETS): %s", pCE->server.string, + if (0 != tcsetattr(0, TCSANOW, &n_tio)) { + Error("[%s] tcsetattr(0,TCSANOW): %s", pCE->server, strerror(errno)); Bye(EX_OSERR); } tcsetpgrp(0, iNewGrp); -# else /* ! HAVE_TERMIOS_H */ - /* stty 9600 raw cs7 - */ - if (-1 == ioctl(0, TIOCGETP, (char *)&sty)) { - Error("[%s] ioctl(0,TIOCGETP): %s", pCE->server.string, - strerror(errno)); - Bye(EX_OSERR); - } - sty.sg_flags &= ~(CBREAK | TANDEM | pCE->pparity->iclr); - sty.sg_flags |= (ECHO | CRMOD | pCE->pparity->iset); - sty.sg_erase = '\b'; - sty.sg_kill = '\025'; - sty.sg_ispeed = pCE->pbaud->irate; - sty.sg_ospeed = pCE->pbaud->irate; - if (-1 == ioctl(0, TIOCSETP, (char *)&sty)) { - Error("[%s] ioctl(0,TIOCSETP): %s", pCE->server.string, - strerror(errno)); - Bye(EX_OSERR); - } - - /* stty undef all tty chars - * (in cbreak mode we may not need to this... but we do) - */ - if (-1 == ioctl(0, TIOCGETC, (char *)&m_tchars)) { - Error("[%s] ioctl(0,TIOCGETC): %s", pCE->server.string, - strerror(errno)); - Bye(EX_OSERR); - } - m_tchars.t_intrc = '\003'; - m_tchars.t_quitc = '\034'; - m_tchars.t_startc = '\021'; - m_tchars.t_stopc = '\023'; - m_tchars.t_eofc = '\004'; - m_tchars.t_brkc = '\033'; - if (-1 == ioctl(0, TIOCSETC, (char *)&m_tchars)) { - Error("[%s] ioctl(0,TIOCSETC): %s", pCE->server.string, - strerror(errno)); - Bye(EX_OSERR); - } - if (-1 == ioctl(0, TIOCGLTC, (char *)&m_ltchars)) { - Error("[%s] ioctl(0,TIOCGLTC): %s", pCE->server.string, - strerror(errno)); - Bye(EX_OSERR); - } - m_ltchars.t_werasc = '\027'; - m_ltchars.t_flushc = '\017'; - m_ltchars.t_lnextc = '\026'; - m_ltchars.t_suspc = '\032'; - m_ltchars.t_dsuspc = '\031'; - if (-1 == ioctl(0, TIOCSLTC, (char *)&m_ltchars)) { - Error("[%s] ioctl(0,TIOCSLTC): %s", pCE->server.string, - strerror(errno)); - Bye(EX_OSERR); - } - - /* give us a process group to work in - */ - ioctl(0, TIOCGPGRP, (char *)&i); -# ifndef SETPGRP_VOID - setpgrp(0, i); -# endif - ioctl(0, TIOCSPGRP, (char *)&iNewGrp); -# ifndef SETPGRP_VOID - setpgrp(0, iNewGrp); -# endif -# endif /* HAVE_TERMIOS_H */ - - close(2); - dup(1); /* better be 2, but it is too late now */ /* if the command is null we should run root's shell, directly * if we can't find root's shell run /bin/sh */ pcShell = "/bin/sh"; - if (pCE->pccmd.used <= 1) { + if (pCE->exec == (char *)0) { static char *apcArgv[] = { "-shell", "-i", (char *)0 }; @@ -627,108 +393,71 @@ VirtDev(pCE) "/bin/sh", "-ce", (char *)0, (char *)0 }; - apcArgv[2] = pCE->pccmd.string; + apcArgv[2] = pCE->exec; ppcArgv = apcArgv; } + + close(2); + dup(1); /* better be 2, but it is too late now */ + execve(pcShell, ppcArgv, environ); - Error("[%s] execve(): %s", pCE->server.string, strerror(errno)); + Error("[%s] execve(): %s", pCE->server, strerror(errno)); Bye(EX_OSERR); return -1; } /* down a console, virtual or real (ksb) + * + * this should be kept pretty simple, 'cause the config file reading code + * can come along and reconfigure a console out from under this - and it + * expects to be able to call ConsDown() to shut it down. so, only mess + * with the "runtime" members of the structure here. */ void #if PROTOTYPES -ConsDown(CONSENT * pCE, fd_set * pfdSet, short downHard) +ConsDown(CONSENT *pCE, FLAG downHard, FLAG force) #else -ConsDown(pCE, pfdSet, downHard) +ConsDown(pCE, downHard, force) CONSENT *pCE; - fd_set *pfdSet; - short downHard; + FLAG downHard; + FLAG force; #endif { - if (-1 != pCE->ipid) { - Debug(1, "ConsDown(): sending pid %lu signal %d", - (unsigned long)pCE->ipid, SIGHUP); + if (force != FLAGTRUE && + !(FileBufEmpty(pCE->fdlog) && FileBufEmpty(pCE->cofile))) { + pCE->ioState = ISFLUSHING; + return; + } + + if (pCE->ipid != 0) { + CONDDEBUG((1, "ConsDown(): sending pid %lu signal %d", + (unsigned long)pCE->ipid, SIGHUP)); kill(pCE->ipid, SIGHUP); - pCE->ipid = -1; + pCE->ipid = 0; } - if (-1 != pCE->fdtty) { - if ((fd_set *) 0 != pfdSet) - FD_CLR(pCE->fdtty, pfdSet); - close(pCE->fdtty); - pCE->fdtty = -1; + if (pCE->cofile != (CONSFILE *)0) { + int cofile = FileFDNum(pCE->cofile); + FD_CLR(cofile, &rinit); + FD_CLR(cofile, &winit); + FileClose(&pCE->cofile); } - if ((CONSFILE *) 0 != pCE->fdlog) { + if (pCE->fdlog != (CONSFILE *)0) { if (pCE->nolog) { TagLogfile(pCE, "Console logging restored"); } TagLogfile(pCE, "Console down"); + FD_CLR(FileFDNum(pCE->fdlog), &winit); FileClose(&pCE->fdlog); - pCE->fdlog = (CONSFILE *) 0; + } + if (pCE->type == EXEC && pCE->execSlaveFD != 0) { + close(pCE->execSlaveFD); + pCE->execSlaveFD = 0; } pCE->fup = 0; pCE->nolog = 0; pCE->autoReUp = 0; pCE->downHard = downHard; -} - -int -#if PROTOTYPES -CheckHostCache(const char *hostname) -#else -CheckHostCache(hostname) - const char *hostname; -#endif -{ - struct hostcache *p; - p = hostcachelist; - while (p != NULL) { - if (0 == strcasecmp(hostname, p->hostname.string)) { - return 1; - } - p = p->next; - } - return 0; -} - -void -#if PROTOTYPES -AddHostCache(const char *hostname) -#else -AddHostCache(hostname) - const char *hostname; -#endif -{ - struct hostcache *n; - if ((struct hostcache *)0 == - (n = (struct hostcache *)calloc(1, sizeof(struct hostcache)))) { - Error("AddHostCache(): calloc(): %s", strerror(errno)); - return; - } - BuildString(hostname, &n->hostname); - n->next = hostcachelist; - hostcachelist = n; -} - -void -#if PROTOTYPES -ClearHostCache(void) -#else -ClearHostCache() -#endif -{ - struct hostcache *p, *n; - p = hostcachelist; - while (p != NULL) { - n = p->next; - if (p->hostname.allocated) - free(p->hostname.string); - free(p); - p = n; - } - hostcachelist = NULL; + pCE->ioState = ISDISCONNECTED; } /* set up a console the way it should be for use to work with it (ksb) @@ -737,26 +466,22 @@ ClearHostCache() */ void #if PROTOTYPES -ConsInit(CONSENT * pCE, fd_set * pfdSet, short useHostCache) +ConsInit(CONSENT *pCE) #else -ConsInit(pCE, pfdSet, useHostCache) +ConsInit(pCE) CONSENT *pCE; - fd_set *pfdSet; - short useHostCache; #endif { time_t tyme; - extern int FallBack PARAMS((STRING *, STRING *)); - - if (!useHostCache) - ClearHostCache(); + extern int FallBack PARAMS((char **, int *)); + int cofile = -1; + int ret; /* clean up old stuff */ if (pCE->fup) { - ConsDown(pCE, pfdSet, 0); - usleep(500000); /* pause 0.50 sec to let things settle a bit */ - ResetMark(); + ConsDown(pCE, FLAGFALSE, FLAGTRUE); + usleep(250000); /* pause 0.25 sec to let things settle a bit */ } pCE->autoReUp = 0; @@ -767,173 +492,175 @@ ConsInit(pCE, pfdSet, useHostCache) /* try to open them again */ - if ((CONSFILE *) 0 == - (pCE->fdlog = - FileOpen(pCE->lfile.string, O_RDWR | O_CREAT | O_APPEND, 0644))) { - Error("[%s] FileOpen(%s): %s: forcing down", pCE->server.string, - pCE->lfile.string, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; + if (pCE->logfile != (char *)0) { + if ((CONSFILE *)0 == + (pCE->fdlog = + FileOpen(pCE->logfile, O_RDWR | O_CREAT | O_APPEND, 0644))) { + Error("[%s] FileOpen(%s): %s: forcing down", pCE->server, + pCE->logfile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } } TagLogfile(pCE, "Console up"); - if (0 != pCE->fvirtual) { - if (-1 == (pCE->fdtty = FallBack(&pCE->acslave, &pCE->dfile))) { - Error("[%s] failed to allocate pseudo-tty: %s: forcing down", - pCE->server.string, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; - } - } else if (pCE->isNetworkConsole) { - struct sockaddr_in port; - struct hostent *hp; - size_t one = 1; - int flags; - fd_set fds; - struct timeval tv; + switch (pCE->type) { + case UNKNOWN: /* shut up gcc */ + break; + case EXEC: + if ((cofile = + FallBack(&pCE->execSlave, &pCE->execSlaveFD)) == -1) { + Error + ("[%s] failed to allocate pseudo-tty: %s: forcing down", + pCE->server, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + if ((pCE->cofile = + FileOpenFD(cofile, simpleFile)) == (CONSFILE *)0) { + Error + ("[%s] FileOpenFD(%d,simpleFile) failed: forcing down", + pCE->server, cofile); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + VirtDev(pCE); + pCE->ioState = ISNORMAL; + break; + case HOST: + { + struct sockaddr_in port; + struct hostent *hp; + size_t one = 1; - if (CheckHostCache(pCE->networkConsoleHost.string)) { - Error("[%s] cached previous timeout: %s: forcing down", - pCE->server.string, pCE->networkConsoleHost.string); - ConsDown(pCE, pfdSet, 1); - return; - } - usleep(100000); /* Not all terminal servers can keep up */ - ResetMark(); + usleep(100000); /* Not all terminal servers can keep up */ #if HAVE_MEMSET - memset((void *)&port, 0, sizeof(port)); + memset((void *)&port, 0, sizeof(port)); #else - bzero((char *)&port, sizeof(port)); + bzero((char *)&port, sizeof(port)); #endif - if ((hp = gethostbyname(pCE->networkConsoleHost.string)) == NULL) { - Error("[%s] gethostbyname(%s): %s: forcing down", - pCE->server.string, pCE->networkConsoleHost.string, - hstrerror(h_errno)); - ConsDown(pCE, pfdSet, 1); - return; - } + if ((hp = gethostbyname(pCE->host)) == NULL) { + Error("[%s] gethostbyname(%s): %s: forcing down", + pCE->server, pCE->host, hstrerror(h_errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } #if HAVE_MEMCPY - memcpy(&port.sin_addr.s_addr, hp->h_addr, hp->h_length); + memcpy(&port.sin_addr.s_addr, hp->h_addr_list[0], + hp->h_length); #else - bcopy(hp->h_addr, &port.sin_addr.s_addr, hp->h_length); + bcopy(hp->h_addr_list[0], &port.sin_addr.s_addr, + hp->h_length); #endif - port.sin_family = hp->h_addrtype; - port.sin_port = htons(pCE->networkConsolePort); + port.sin_family = hp->h_addrtype; + port.sin_port = htons(pCE->port); - if ((pCE->fdtty = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - Error("[%s] socket(AF_INET,SOCK_STREAM): %s: forcing down", - pCE->server.string, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; - } - if (setsockopt - (pCE->fdtty, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, - sizeof(one)) < 0) { - Error("[%s] setsockopt(%u,SO_KEEPALIVE): %s: forcing down", - pCE->server.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; - } + if ((cofile = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + Error + ("[%s] socket(AF_INET,SOCK_STREAM): %s: forcing down", + pCE->server, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + if (setsockopt + (cofile, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, + sizeof(one)) < 0) { + Error + ("[%s] setsockopt(%u,SO_KEEPALIVE): %s: forcing down", + pCE->server, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } - if ((flags = fcntl(pCE->fdtty, F_GETFL)) >= 0) { - flags |= O_NONBLOCK; - if (fcntl(pCE->fdtty, F_SETFL, flags) < 0) { - Error("[%s] fcntl(%u,F_SETFL): %s: forcing down", - pCE->server.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if (!SetFlags(cofile, O_NONBLOCK, 0)) { + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + + if ((ret = + connect(cofile, (struct sockaddr *)&port, + sizeof(port))) + < 0) { + if (errno != EINPROGRESS) { + Error("[%s] connect(%u): %s: forcing down", + pCE->server, cofile, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + } + } + if ((pCE->cofile = + FileOpenFD(cofile, simpleSocket)) == (CONSFILE *)0) { + Error + ("[%s] FileOpenFD(%d,simpleSocket) failed: forcing down", + pCE->server, cofile); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return; } - } else { - Error("[%s] fcntl(%u,F_GETFL): %s: forcing down", - pCE->server.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; - } + if (ret == 0) { + pCE->ioState = ISNORMAL; + pCE->stateTimer = 0; + pCE->fup = 1; + } else { + pCE->ioState = INCONNECT; + pCE->stateTimer = time((time_t *)0) + CONNECTTIMEOUT; + pCE->fup = 1; + } + break; + case DEVICE: + if (-1 == + (cofile = open(pCE->device, O_RDWR | O_NDELAY, 0600))) { - if (connect(pCE->fdtty, (struct sockaddr *)&port, sizeof(port)) < - 0) { - if (errno != EINPROGRESS) { - Error("[%s] connect(%u): %s: forcing down", - pCE->server.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); + Error("[%s] open(%s): %s: forcing down", pCE->server, + pCE->device, strerror(errno)); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return; } - } - - tv.tv_sec = CONNECTTIMEOUT; - tv.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(pCE->fdtty, &fds); - - if ((one = select(pCE->fdtty + 1, NULL, &fds, NULL, &tv)) < 0) { - Error("[%s] select(%u): %s: forcing down", pCE->server.string, - pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; - } - - if (one == 0) { /* Timeout */ - AddHostCache(pCE->networkConsoleHost.string); - Error("[%s] connect timeout: forcing down", pCE->server.string, - strerror(errno)); - ConsDown(pCE, pfdSet, 1); - return; - } else { /* Response */ - socklen_t slen; - flags = 0; - slen = sizeof(flags); - /* So, getsockopt seems to return -1 if there is something - interesting in SO_ERROR under solaris...sheesh. So, - the error message has the small change it's not accurate. */ - if (getsockopt - (pCE->fdtty, SOL_SOCKET, SO_ERROR, (char *)&flags, - &slen) < 0) { - Error("[%s] getsockopt(%u,SO_ERROR): %s: forcing down", - pCE->server.string, pCE->fdtty, strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if ((pCE->cofile = + FileOpenFD(cofile, simpleFile)) == (CONSFILE *)0) { + Error + ("[%s] FileOpenFD(%d,simpleFile) failed: forcing down", + pCE->server, cofile); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); return; } - if (flags != 0) { - Error("[%s] connect(%u): %s: forcing down", - pCE->server.string, pCE->fdtty, strerror(flags)); - ConsDown(pCE, pfdSet, 1); - return; - } - } + TtyDev(pCE); + pCE->ioState = ISNORMAL; + break; + } -# if POKE_ANNEX - /* - * Poke the connection to get the annex to wake up and - * register this connection. - */ - write(pCE->fdtty, "\r\n", 2); -# endif - } else if (-1 == - (pCE->fdtty = - open(pCE->dfile.string, O_RDWR | O_NDELAY, 0600))) { - Error("[%s] open(%s): %s: forcing down", pCE->server.string, - pCE->dfile.string, strerror(errno)); - ConsDown(pCE, pfdSet, 1); + if (!pCE->fup) { + pCE->ioState = ISDISCONNECTED; return; } - FD_SET(pCE->fdtty, pfdSet); - /* ok, now setup the device - */ - if (pCE->fvirtual) { - VirtDev(pCE); - } else if (pCE->isNetworkConsole) { - pCE->fup = 1; - } else { - TtyDev(pCE, pfdSet); + switch (pCE->type) { + case UNKNOWN: /* shut up gcc */ + break; + case EXEC: + Verbose("[%s] pid %lu on %s", pCE->server, pCE->ipid, + pCE->execSlave); + break; + case HOST: + Verbose("[%s] port %hu on %s", pCE->server, pCE->port, + pCE->host); + break; + case DEVICE: + Verbose("[%s] at %s%c on %s", pCE->server, pCE->baud->acrate, + pCE->parity->key[0], pCE->device); + break; } + FD_SET(cofile, &rinit); + if (maxfd < cofile + 1) + maxfd = cofile + 1; + /* If we have marks, adjust the next one so that it's in the future */ if (pCE->nextMark > 0) { - tyme = time((time_t *) 0); + tyme = time((time_t *)0); if (tyme >= pCE->nextMark) { /* Add as many pCE->mark values as necessary so that we move * beyond the current time. @@ -943,8 +670,210 @@ ConsInit(pCE, pfdSet, useHostCache) } } - if (pCE->downHard && pCE->fup) { - Msg("[%s] console up", pCE->server.string); - pCE->downHard = 0; + if (pCE->downHard == FLAGTRUE) { + Msg("[%s] console up", pCE->server); + pCE->downHard = FLAGFALSE; } } + +int +#if PROTOTYPES +AddrsMatch(char *addr1, char *addr2) +#else +AddrsMatch(addr1, addr2) + char *addr1; + char *addr2; +#endif +{ + /* so, since we might use inet_addr, we're going to use + * (in_addr_t)(-1) as a sign of an invalid ip address. + * sad, but true. + */ + in_addr_t inAddr1 = (in_addr_t) (-1); + in_addr_t inAddr2 = (in_addr_t) (-1); +#if HAVE_INET_ATON + struct in_addr inetAddr1; + struct in_addr inetAddr2; +#endif + + /* first try simple character string match */ + if (strcasecmp(addr1, addr2) == 0) + return 1; + + /* now try ip address match (could have leading zeros or something) */ +#if HAVE_INET_ATON + if (inet_aton(addr1, &inetAddr1) != 0) + inAddr1 = inetAddr1.s_addr; + if (inet_aton(addr2, &inetAddr2) != 0) + inAddr2 = inetAddr2.s_addr; +#else + inAddr1 = inet_addr(addr1); + inAddr2 = inet_addr(addr2); +#endif + + /* if both are ip addresses, we just match */ + if (inAddr1 != (in_addr_t) (-1) && inAddr2 != (in_addr_t) (-1)) + return ! +#if HAVE_MEMCMP + memcmp(&inAddr1, &inAddr2, sizeof(inAddr1)) +#else + bcmp(&inAddr1, &inAddr2, sizeof(inAddr1)) +#endif + ; + + /* both are hostnames...this sucks 'cause we have to copy one + * list and compare it to the other + */ + if (inAddr1 == (in_addr_t) (-1) && inAddr2 == (in_addr_t) (-1)) { + struct hostent *he; + int i, j, c; + in_addr_t *addrs; + + if ((he = gethostbyname(addr1)) == (struct hostent *)0) { + Error("AddrsMatch(): gethostbyname(%s): %s", addr1, + hstrerror(h_errno)); + return 0; + } + if (4 != he->h_length || AF_INET != he->h_addrtype) { + Error + ("AddrsMatch(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)", + addr1, he->h_length, AF_INET, he->h_addrtype); + return 0; + } + for (i = 0; he->h_addr_list[i] != (char *)0; i++); + c = i; + addrs = (in_addr_t *) calloc(i, sizeof(in_addr_t)); + if (addrs == (in_addr_t *) 0) + OutOfMem(); + for (i = 0; i < c; i++) { +#if HAVE_MEMCPY + memcpy(&(addrs[i]), he->h_addr_list[i], he->h_length); +#else + bcopy(he->h_addr_list[i], &(addrs[i]), he->h_length); +#endif + } + + /* now process the second hostname */ + if ((he = gethostbyname(addr2)) == (struct hostent *)0) { + Error("AddrsMatch(): gethostbyname(%s): %s", addr2, + hstrerror(h_errno)); + free(addrs); + return 0; + } + if (4 != he->h_length || AF_INET != he->h_addrtype) { + Error + ("AddrsMatch(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)", + addr2, he->h_length, AF_INET, he->h_addrtype); + free(addrs); + return 0; + } + for (j = 0; he->h_addr_list[j] != (char *)0; j++) { + for (i = 0; i < c; i++) { + if ( +#if HAVE_MEMCMP + memcmp(&(addrs[i]), he->h_addr_list[j], + he->h_length) +#else + bcmp(&(addrs[i]), he->h_addr_list[j], he->h_length) +#endif + == 0) { + free(addrs); + return 1; + } + } + } + free(addrs); + } else { /* one hostname, one ip addr */ + in_addr_t *iaddr; + char *addr; + struct hostent *he; + int i; + + if (inAddr1 == (in_addr_t) (-1)) { + addr = addr1; + iaddr = &inAddr2; + } else { + addr = addr2; + iaddr = &inAddr1; + } + if ((he = gethostbyname(addr)) == (struct hostent *)0) { + Error("AddrsMatch(): gethostbyname(%s): %s", addr, + hstrerror(h_errno)); + return 0; + } + if (4 != he->h_length || AF_INET != he->h_addrtype) { + Error + ("AddrsMatch(): wrong address size (4 != %d) or address family (%d != %d)", + he->h_length, AF_INET, he->h_addrtype); + return 0; + } + for (i = 0; he->h_addr_list[i] != (char *)0; i++) { + if ( +#if HAVE_MEMCMP + memcmp(iaddr, he->h_addr_list[i], he->h_length) +#else + bcmp(iaddr, he->h_addr_list[i], he->h_length) +#endif + == 0) + return 1; + } + } + return 0; +} + +/* thread ther list of uniq console server machines, aliases for (ksb) + * machines will screw us up + */ +REMOTE * +#if PROTOTYPES +FindUniq(REMOTE *pRCAll) +#else +FindUniq(pRCAll) + REMOTE *pRCAll; +#endif +{ + REMOTE *pRC; + + /* INV: tail of the list we are building always contains only + * uniq hosts, or the empty list. + */ + if (pRCAll == (REMOTE *)0) + return (REMOTE *)0; + + pRCAll->pRCuniq = FindUniq(pRCAll->pRCnext); + + /* if it is in the returned list of uniq hosts, return that list + * else add us by returning our node + */ + for (pRC = pRCAll->pRCuniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { + if (AddrsMatch(pRC->rhost, pRCAll->rhost)) + return pRCAll->pRCuniq; + } + return pRCAll; +} + +void +#if PROTOTYPES +DestroyRemoteConsole(REMOTE *pRCList) +#else +DestroyRemoteConsole(pRCList) + REMOTE *pRCList; +#endif +{ + NAMES *name = (NAMES *)0; + + if (pRCList == (REMOTE *)0) + return; + if (pRCList->rserver != (char *)0) + free(pRCList->rserver); + if (pRCList->rhost != (char *)0) + free(pRCList->rhost); + while (pRCList->aliases != (NAMES *)0) { + name = pRCList->aliases->next; + if (pRCList->aliases->name != (char *)0) + free(pRCList->aliases->name); + free(pRCList->aliases); + pRCList->aliases = name; + } + free(pRCList); +} diff --git a/conserver/consent.h b/conserver/consent.h index c431416..1b378b1 100644 --- a/conserver/consent.h +++ b/conserver/consent.h @@ -1,5 +1,5 @@ /* - * $Id: consent.h,v 5.36 2003-03-17 08:54:53-08 bryan Exp $ + * $Id: consent.h,v 5.46 2003-08-18 20:01:16-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -46,60 +46,111 @@ typedef struct baud { /* a baud rate table */ } BAUD; typedef struct parity { /* a parity bits table */ - char ckey; + char *key; int iset; int iclr; } PARITY; +typedef enum consType { + UNKNOWN = 0, + DEVICE, + EXEC, + HOST +} CONSTYPE; + +typedef struct names { + char *name; + struct names *next; +} NAMES; + +typedef struct consentUsers { + NAMES *user; + struct consentUsers *next; +} CONSENTUSERS; + +/* we calloc() these things, so we're trying to make everything be + * "empty" when it's got a zero value + */ typedef struct consent { /* console information */ - STRING server; /* server name */ - STRING dfile; /* device file */ - STRING lfile; /* log file */ - BAUD *pbaud; /* the baud on this console port */ - PARITY *pparity; /* the parity on this line */ + /*** config file settings ***/ + char *server; /* server name */ + CONSTYPE type; /* console type */ + NAMES *aliases; /* aliases for server name */ + /* type == DEVICE */ + char *device; /* device file */ + BAUD *baud; /* the baud on this console port */ + PARITY *parity; /* the parity on this line */ + FLAG hupcl; /* use HUPCL */ + FLAG cstopb; /* use two stop bits */ + FLAG ixon; /* XON/XOFF flow control on output */ + FLAG ixany; /* any character to restart output */ + FLAG ixoff; /* XON/XOFF flow control on input */ +#if defined(CRTSCTS) + FLAG crtscts; /* use hardware flow control */ +#endif + /* type == HOST */ + char *host; /* hostname */ + unsigned short port; /* port number */ + /* type == EXEC */ + char *exec; /* exec command */ + /* */ + char *master; /* master hostname */ + /* */ + unsigned short breakNum; /* break type [1-9] */ + /* */ + char *logfile; /* logfile */ + /* timestamp stuff */ int mark; /* Mark (chime) interval */ long nextMark; /* Next mark (chime) time */ - unsigned short breakType; /* break type [1-9] */ - unsigned short autoReUp; /* is it coming back up automatically? */ - unsigned short downHard; /* did it go down unexpectedly? */ + FLAG activitylog; /* log attach/detach/bump */ + FLAG breaklog; /* log breaks sent */ + /* options */ + FLAG ondemand; /* bring up on-demand */ + FLAG reinitoncc; /* open if down on client connect */ + FLAG striphigh; /* strip high-bit of console data */ + FLAG autoreinit; /* auto-reinitialize if failed */ + FLAG unloved; /* copy "unloved" data to stdout */ - /* Used if network console */ - int isNetworkConsole; - STRING networkConsoleHost; - unsigned short networkConsolePort; - int telnetState; - - /* used if virtual console */ - STRING acslave; /* pseudo-device slave side */ - int fvirtual; /* is a pty device we use as a console */ - STRING pccmd; /* virtual console command */ - pid_t ipid; /* pid of virtual command */ - - /* only used in child */ - int nolog; /* don't log output */ + /*** runtime settings ***/ CONSFILE *fdlog; /* the local log file */ - int fdtty; /* the port to talk to machine on */ - int activitylog; /* log attach/detach/bump */ - int breaklog; /* log breaks sent */ - unsigned short fup; /* we setup this line? */ - unsigned short fronly; /* we can only read this console */ - struct client *pCLon; /* clients on this console */ - struct client *pCLwr; /* client that is writting on console */ + CONSFILE *cofile; /* the port to talk to machine on */ + char *execSlave; /* pseudo-device slave side */ + int execSlaveFD; /* fd of slave side */ + pid_t ipid; /* pid of virtual command */ + STRING *wbuf; /* write() buffer */ + int wbufIAC; /* next IAC location in wbuf */ + IOSTATE ioState; /* state of the socket */ + time_t stateTimer; /* timer for ioState states */ + + /*** state information ***/ char acline[132 * 2 + 2]; /* max chars we will call a line */ int iend; /* length of data stored in acline */ + int telnetState; /* state for telnet negotiations */ + unsigned short autoReUp; /* is it coming back up automatically? */ + FLAG downHard; /* did it go down unexpectedly? */ + unsigned short nolog; /* don't log output */ + unsigned short fup; /* we setup this line? */ + unsigned short fronly; /* we can only read this console */ + + /*** list management ***/ + struct client *pCLon; /* clients on this console */ + struct client *pCLwr; /* client that is writting on console */ + CONSENTUSERS *rw; /* rw users */ + CONSENTUSERS *ro; /* ro users */ struct consent *pCEnext; /* next console entry */ } CONSENT; -struct hostcache { - STRING hostname; - struct hostcache *next; -}; +typedef struct remote { /* console at another host */ + struct remote *pRCnext; /* next remote console we know about */ + struct remote *pRCuniq; /* list of uniq remote servers */ + char *rserver; /* remote server name */ + char *rhost; /* remote host to call to get it */ + NAMES *aliases; /* aliases for remote server name */ +} REMOTE; extern PARITY *FindParity PARAMS((char *)); extern BAUD *FindBaud PARAMS((char *)); -extern void ConsInit PARAMS((CONSENT *, fd_set *, short)); -extern void ConsDown PARAMS((CONSENT *, fd_set *, short)); -extern int CheckHostCache PARAMS((const char *)); -extern void AddHostCache PARAMS((const char *)); -extern void ClearHostCache PARAMS((void)); -extern void ClearHostCache PARAMS((void)); +extern void ConsInit PARAMS((CONSENT *)); +extern void ConsDown PARAMS((CONSENT *, FLAG, FLAG)); +extern REMOTE *FindUniq PARAMS((REMOTE *)); +extern void DestroyRemoteConsole PARAMS((REMOTE *)); diff --git a/conserver/conserver.man b/conserver/conserver.man index 679c6ff..e8a1ad9 100644 --- a/conserver/conserver.man +++ b/conserver/conserver.man @@ -1,24 +1,39 @@ .\" @(#)conserver.8 01/06/91 OSU CIS; Thomas A. Fine -.\" $Id: conserver.man,v 1.32 2003-04-08 14:05:59-07 bryan Exp $ -.TH CONSERVER 8 "Local" +.\" $Id: conserver.man,v 1.38 2003-09-22 08:33:41-07 bryan Exp $ +.TH CONSERVER 8 "2003-09-22" "conserver-8.0.0" "conserver" .SH NAME conserver \- console server daemon .SH SYNOPSIS -\fBconserver\fP [\fB\-7dDEFhinoRuvV\fP] [\fB\-a\fP \fItype\fP] -[\fB\-m\fP \fImax\fP] -[\fB\-M\fP \fIaddr\fP] [\fB\-p\fP \fIport\fP] [\fB\-b\fP \fIport\fP] -[\fB\-c\fP \fIcred\fP] [\fB\-C\fP \fIconfig\fP] [\fB\-P\fP \fIpasswd\fP] -[\fB\-L\fP \fIlogfile\fP] [\fB\-O\fP \fImin\fP] +.B conserver +.RB [ \-7dDEFhinoRSuvV ] +.RB [ \-a +.IR type ] +.RB [ \-m +.IR max ] +.RB [ \-M +.IR addr ] +.RB [ \-p +.IR port ] +.RB [ \-b +.IR port ] +.RB [ \-c +.IR cred ] +.RB [ \-C +.IR config ] +.RB [ \-P +.IR passwd ] +.RB [ \-L +.IR logfile ] +.RB [ \-O +.IR min ] .SH DESCRIPTION .B Conserver is the daemon that manages remote access to system consoles by multiple users via the .BR console (1) -client program -and logs all console output. -It can connect to consoles via local serial ports -or terminal servers that allow network access, -or to any external program. +client program and logs all console output. +It can connect to consoles via local serial ports, terminal +servers that allow network access, or to any external program. .PP When started, .B conserver @@ -28,112 +43,139 @@ file for details of each console it should manage, including serial port or network parameters and logging options. (Also, in environments where multiple servers share a cf file, any server is able to refer clients to the particular server -managing a requested console, -so that the client need not have knowledge of the -distribution of consoles among servers.) +managing a requested console, so that the client need not have +knowledge of the distribution of consoles among servers.) .B Conserver forks a child for each group of consoles it must manage and assigns each process a port number to listen on. The maximum number of consoles managed by each child process is set using -\fB-m\fP option. +.B \-m +option. The .BR console (1) client program communicates with the master console server process to find the port (and host, in a multi-server configuration) on which the appropriate child is listening. -The master conserver process forks a new process to handle each -incoming client connection (which should be very short-lived, since it's -duty is to redirect the client to a child). .B Conserver restricts connections from clients based on the host access section of its .BR conserver.cf (5) -and authenticates users against its +file, restricts users based on the console access lists of the +.BR conserver.cf (5) +file, and authenticates +users against its .BR conserver.passwd (5) file. .B Conserver can also restrict clients using the tcp-wrappers package (enabled -using \fB--with-libwrap\fP). This authentication is done before consulting +using +.BR --with-libwrap ). +This authentication is done before consulting the .BR conserver.cf (5) access list. .PP .B Conserver -completely controls any connection to a controlled host. -All escape sequences given by the user to \fBconsole\fP +completely controls any connection to a console. +All escape sequences given by the user to +.B console are passed to the server without interpretation. The server recognizes and processes all escape sequences, -except the suspend sequence, which is -recognized by the server and -sent as a TCP out-of-band command from the server to the client. +The suspend sequence is recognized by the server and sent back to the +client as a TCP out-of-band command, which the client processes. .PP -The \fBconserver\fP parent process will automatically respawn any child -process that dies. The following signals are propagated by the parent -process to its children. -.TP +The +.B conserver +parent process will automatically respawn any child process that dies. +The following signals are propagated by the parent process to its children. +.TP 10 SIGTERM Close all connections and exit. .TP SIGHUP -Reread the configuration file. New consoles are managed by -forking off new childen, deleted consoles (and their clients) are dropped, +Reread the configuration file. +New consoles are managed by forking off new childen, deleted +consoles (and their clients) are dropped, and changes to consoles are done "in place", resetting the console -port (bringing it down and up) only when necessary. The console name is -used to determine when consoles have been added/removed/changed. All -actions performed by SIGUSR2 are also performed. +port (bringing it down and up) only when necessary. +The console name is used to determine when consoles +have been added/removed/changed. +All actions performed by SIGUSR2 are also performed. .TP SIGUSR1 -Try to connect to any consoles marked as -down. This can come in handy if you had a terminal server (or more) +Try to connect to any consoles marked as down. +This can come in handy if you had a terminal server (or more) that wasn't accepting connections at startup and you want -\fBconserver\fP to try to reconnect to all those downed ports. +.B conserver +to try to reconnect to all those downed ports. .TP SIGUSR2 Close and reopen all console logfiles -and, if in daemon mode (\fB\-d\fP option), -the error logfile (see the \fB\-L\fP option). All actions performed by -SIGUSR1 are also performed. +and, if in daemon mode +.RB ( \-d +option), the error logfile (see the +.BR \-L +option). +All actions performed by SIGUSR1 are also performed. .PP -Slave hosts which have no current -.BR console (1) +Consoles which have no current client connection might produce important error messages. -With the \fB\-u\fP option, these unloved errors are labeled with a machine name +With the +.B \-u +option, these ``unloved'' errors are labeled with a machine name and output on stdout (or, in daemon mode, to the logfile). This allows a live operator or an automated log scanner to find otherwise unseen errors by watching in a single location. .PP -\fBConserver\fP must be run as root if it is to bind to a port under -1024 or if it must read protected password files (like shadow passwords) +.B Conserver +must be run as root if it is to bind to a port under 1024 or if it +must read protected password files (like shadow passwords) for authentication (see .BR conserver.passwd (5)). -Otherwise, it may be run by any user, with \fB\-p\fP used to specify -a port above 1024. +Otherwise, it may be run by any user, with +.B \-p +used to specify a port above 1024. .PP -If encryption has been built into the code (\fB--with-openssl\fP), +If encryption has been built into the code +.RB ( --with-openssl ), encrypted client connections (without certificate exchanges) happen -by default. To add certificate exchanges, use the \fB-c\fP option with -the client and server. For authentication of the certificates to work, +by default. +To add certificate exchanges, use the +.B \-c +option with the client and server. +For authentication of the certificates to work, the signing certificate must be properly trusted, which usually means -the public portion is in \fIOPENSSL_ROOT\fP\fB/ssl/certs\fP (on both -the client and server sides). See the sample self-signing certficate -making script \fBcontrib/maketestcerts\fP for further clues. To allow +the public portion is in +.IB OPENSSL_ROOT /ssl/certs +(on both the client and server sides). +See the sample self-signing certficate making script +.B contrib/maketestcerts +for further clues. +To allow non-encrypted client connections (in addition to encrypted client -connections), use the \fB-E\fP option. +connections), use the +.B \-E +option. .SH OPTIONS .PP -Options may be given as separate arguments (e.g., \fB\-n -d\fP) -or clustered (e.g., \fB\-nd\fP). +Options may be given as separate arguments (e.g., +.B \-n +.BR \-d ) +or clustered (e.g., +.BR \-nd ). Options and their arguments may be separated by optional white space. Option arguments containing spaces or other characters special to the shell must be quoted. -.TP +.TP 12 .B \-7 Strip the high bit off of all data received, -whether from the \fBconsole\fP client or from the console device, -before any processing occurs. +whether from the +.B console +client or from the console device, before any processing occurs. .TP .BI \-a type Set the default access type for incoming connections from -\fBconsole\fP clients: +.B console +clients: .RB ` r ' for refused (the default), .RB ` a ' @@ -146,43 +188,60 @@ the access section of .TP .BI \-b port Set the base port for children to listen on. -Each child starts looking for free ports at \fIport\fP +Each child starts looking for free ports at +.I port and working upward, trying a maximum number of ports equal to twice the maximum number of groups. If no free ports are available in that range, -\fBconserver\fP exits. -By default, \fBconserver\fP lets the operating system choose -a free port. +.B conserver +exits. +By default, +.B conserver +lets the operating system choose a free port. .TP .BI \-c cred -Load an SSL certificate and key from the PEM encoded file \fIcred\fP. +Load an SSL certificate and key from the PEM encoded file +.IR cred . .TP .BI \-C config -Read configuration information from the file \fIconfig\fP. -The default \fIconfig\fP may be changed at compile time using the -\fB--with-cffile\fP option. +Read configuration information from the file +.IR config . +The default +.I config +may be changed at compile time using the +.B --with-cffile +option. .TP .B \-d -Become a daemon. Disconnects from the controlling terminal and sends -all output to the logfile (see \fB\-L\fP). +Become a daemon. +Disconnects from the controlling terminal and sends +all output to the logfile (see +.BR \-L ). .TP .B \-D -Enable debugging output, sent to stderr. Multiple \fB-D\fP options -increases debug output. +Enable debugging output, sent to stderr. +Multiple +.B \-D +options increases debug output. .TP .B \-E -If encryption has been built into the code (\fB--with-openssl\fP), -encrypted client connections are a requirement. This option allows -non-encrypted clients (as well as encrypted clients) to connect to -consoles. +If encryption has been built into the code +.RB ( --with-openssl ), +encrypted client connections are a requirement. +This option allows non-encrypted clients (as well as encrypted clients) to +connect to consoles. .TP .B \-F -Do not automatically reinitialize failed (unexpectedly closed) -consoles. If the console is a program (`|' syntax) and it closes -with a zero exit status, the console is reinitialized regardless -of this option. Without this option, a console is immediately reopened, +Do not automatically reinitialize failed (unexpectedly closed) consoles. +If the console is a program (`|' syntax) and it closes with a zero +exit status, the console is reinitialized regardless of this option. +Without this option, a console is immediately reopened, and if that fails, retried every minute until successful. -This option has no effect on the \fB-o\fP and \fB-O\fP options. +This option has no effect on the +.B \-o +and +.B \-O +options. .TP .B \-h Output a brief help message. @@ -191,24 +250,34 @@ Output a brief help message. Initiate console connections on demand (and close them when not used). .TP .BI \-L logfile -Log errors and informational messages to \fIlogfile\fP -after startup in daemon mode (\fB\-d\fP). +Log errors and informational messages to +.I logfile +after startup in daemon mode +.RB ( \-d ). This option does not apply when not running in daemon mode. -The default \fIlogfile\fP may be changed at compile time using the -\fB--with-logfile\fP option. +The default +.I logfile +may be changed at compile time using the +.B --with-logfile +option. .TP .BI \-m max Set the maximum consoles managed per process. -The default \fImax\fP may be changed at compile time using the -\fB--with-maxmemb\fP option. +The default +.I max +may be changed at compile time using the +.B --with-maxmemb +option. .TP .BI \-M addr -Set the address to listen on. This allows conserver to bind to a +Set the address to listen on. +This allows conserver to bind to a particular IP address (like `127.0.0.1') instead of all interfaces. The default is to bind to all addresses. .TP .B \-n -Obsolete (now a no-op); see \fB\-u\fP. +Obsolete (now a no-op); see +.BR \-u . .TP .B \-o Normally, a client connecting to a ``downed'' console does just that. @@ -216,45 +285,103 @@ Using this option, the server will automatically attempt to open (``bring up'') the console when the client connects. .TP .BI \-O min -Enable periodic attempts (every \fImin\fP minutes) to open (``bring up'') -all downed consoles (similar to sending a SIGUSR1). +Enable periodic attempts (every +.I min +minutes) to open (``bring up'') all downed +consoles (similar to sending a SIGUSR1). .TP .BI \-p port Set the TCP port for the master process to listen on. This may be either a port number or a service name. -The default \fIport\fP, ``conserver'' (typically 782), -may be changed at compile time using the \fB--with-port\fP option. +The default +.IR port , +``conserver'' (typically 782), +may be changed at compile time using the +.B --with-port +option. .TP .BI \-P passwd -Read the table of authorized user data from the file \fIpasswd\fP. -The default \fIpasswd\fP may be changed at compile time using the -\fB--with-pwdfile\fP option. +Read the table of authorized user data from the file +.IR passwd . +The default +.I passwd +may be changed at compile time using the +.B --with-pwdfile +option. .TP .B \-R -Disable automatic client redirection to other conserver hosts. This -means informational commands like \fB-w\fP and \fB-i\fP will only show -the status of the local conserver host and attempts to connect to -remote consoles will result in an informative message to the user. +Disable automatic client redirection to other conserver hosts. +This +means informational commands like +.B \-w +and +.B \-i +will only show the status of the local conserver host and attempts to +connect to remote consoles will result in an informative message to the user. +.TP +.B \-S +Do not run the server, just perform a syntax check of configuration file and +exit with a non-zero value if there is an error. .TP .B \-u -Send unloved console output to \fBconserver\fP's stdout -(which, in daemon mode, is redirected to the logfile). +Send unloved console output to +.BR conserver 's +stdout (which, in daemon mode, is redirected to the logfile). This applies to all consoles to which no user is attached, -independent of whether logging of individual consoles is enabled -via \fBconserver.cf\fP entries. +independent of whether logging of individual consoles is enabled via +.B conserver.cf +entries. .TP .B \-v Echo the configuration as it is being read (be verbose). .TP .B \-V -Output the version number and settings of the \fBconserver\fP +Output the version number and settings of the +.B conserver program and then exit. +.SH PROTOCOL +.PP +The protocol used to interact with the +.B conserver +daemon has two basic styles. +The first style is the initial line-based mode, which occurs before +connecting to a console. +The second style is the character-based, escape-sequence mode, while +connected to a console. +.PP +The initial line-based mode begins the same for both the master process +and it's children. +Upon a successful (non-rejected) client connection, an ``ok'' is sent. +The client then issues a command and the server responds to it with a +result string (``ok'' being the sign of success for most commands). +The commands available are ``help'', ``ssl'' (if +SSL was built into the code), ``login'', and ``exit''. +Using the ``login'' command, the client authenticates and gains access to +the extended command set. +This is where the master process and it's children differ. +The master process gives the client access to global commands, and the +child provides commands for interacting with the consoles it manages. +The ``help'' command, in both cases, will provide a complete +list of commands and a short description of what they do. +.PP +The second, character-based, style of interaction occurs when the client +issues the ``call'' command with a child process. +This command connects the client to a console and, at that point, relays +all traffic between the client and the console. +There is no more command-based interaction between the client and the server, +any interaction with the server is done with the default escape sequence. +.PP +This is, by no means, a complete description of the entire client/server +interaction. +It is, however, a brief explanation in order to give a idea of +what the program does. .SH FILES .PP The following default file locations may be overridden at compile time or by the command-line options described above. -Run \fBconserver \-V\fP (with no other options) to see -the defaults set at compile time. +Run +.B conserver \-V +(with no other options) to see the defaults set at compile time. .PP .PD 0 .TP 25 @@ -278,14 +405,8 @@ Additionally, output from individual consoles may be logged to separate files specified in .BR conserver.cf (5). .SH BUGS -SSL encryption only occurs when connecting to a single console, not -on all client/server activity. The \fB-q\fP/\fB-Q\fP quit command will -pass the root password in the clear. Other info-type -options (like \fB-i\fP, \fB-w\fP, etc) -are all sent unencrypted as well. This should be fixed soon. -.PP -I'm sure there are more, I just don't know where they are. Please -let me know if you find any. +I'm sure there are bugs, I just don't know where they are. +Please let me know if you find any. .SH AUTHORS Thomas A. Fine, Ohio State Computer Science .br diff --git a/conserver/convert.c b/conserver/convert.c new file mode 100644 index 0000000..7f5cbe0 --- /dev/null +++ b/conserver/convert.c @@ -0,0 +1,511 @@ +/* + * $Id: convert.c,v 1.7 2003-08-15 14:24:39-07 bryan Exp $ + * + * Copyright conserver.com, 2000 + * + * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) + * + * Copyright GNAC, Inc., 1998 + */ + +/* + * Copyright (c) 1990 The Ohio State University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that: (1) source distributions retain this entire copyright + * notice and comment, and (2) distributions including binaries display + * the following acknowledgement: ``This product includes software + * developed by The Ohio State University and its contributors'' + * in the documentation or other materials provided with the distribution + * and in all advertising materials mentioning features or use of this + * software. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +/* + * Network console modifications by Robert Olson, olson@mcs.anl.gov. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +void +DestroyDataStructures() +{ +} + +char * +#if PROTOTYPES +ReadLine2(FILE *fp, STRING *save, int *iLine) +#else +ReadLine2(fp, save, iLine) + FILE *fp; + STRING *save; + int *iLine; +#endif +{ + static char buf[1024]; + char *wholeline = (char *)0; + char *ret = (char *)0; + int i, buflen, peek, commentCheck = 1, comment = 0; + static STRING *bufstr = (STRING *)0; + static STRING *wholestr = (STRING *)0; + + if (bufstr == (STRING *)0) + bufstr = AllocString(); + if (wholestr == (STRING *)0) + wholestr = AllocString(); + peek = 0; + wholeline = (char *)0; + BuildString((char *)0, bufstr); + BuildString((char *)0, wholestr); + while (save->used || ((ret = fgets(buf, sizeof(buf), fp)) != (char *)0) + || peek) { + /* If we have a previously saved line, use it instead */ + if (save->used) { + strcpy(buf, save->string); + BuildString((char *)0, save); + } + + if (peek) { + /* End of file? Never mind. */ + if (ret == (char *)0) + break; + + /* If we don't have a line continuation and we've seen + * some worthy data + */ + if (!isspace((int)buf[0]) && (wholeline != (char *)0)) { + BuildString((char *)0, save); + BuildString(buf, save); + break; + } + + peek = 0; + } + + if (commentCheck) { + for (i = 0; buf[i] != '\000'; i++) + if (!isspace((int)buf[i])) + break; + if (buf[i] == '#') { + comment = 1; + commentCheck = 0; + } else if (buf[i] != '\000') { + commentCheck = 0; + } + } + + /* Check for EOL */ + buflen = strlen(buf); + if ((buflen >= 1) && (buf[buflen - 1] == '\n')) { + (*iLine)++; /* Finally have a whole line */ +/* if (comment == 0 && commentCheck == 0) { */ + /* Finish off the chunk without the \n */ + buf[buflen - 1] = '\000'; + BuildString(buf, bufstr); + wholeline = BuildString(bufstr->string, wholestr); +/* }*/ + peek = 1; + comment = 0; + commentCheck = 1; + BuildString((char *)0, bufstr); + } else { + /* Save off the partial chunk */ + BuildString(buf, bufstr); + } + } + + /* If we hit the EOF and weren't peeking ahead + * and it's not a comment + */ + /* + if (!peek && (ret == (char *)0) && (comment == 0) && + (commentCheck == 0)) { + */ + if (!peek && (ret == (char *)0)) { + (*iLine)++; + wholeline = BuildString(bufstr->string, wholestr); + if (wholeline[0] == '\000') + wholeline = (char *)0; + } + + CONDDEBUG((1, "ReadLine2(): returning <%s>", + (wholeline != (char *)0) ? wholeline : "")); + return wholeline; +} + +/* read in the configuration file, fill in all the structs we use (ksb) + * to manage the consoles + */ +void +#if PROTOTYPES +ReadCfg(char *pcFile, FILE *fp) +#else +ReadCfg(pcFile, fp) + char *pcFile; + FILE *fp; +#endif +{ + int iLine; + unsigned char *acIn; + static STRING *acInSave = (STRING *)0; + char *acStart; + static STRING *logDirectory = (STRING *)0; + static STRING *defMark = (STRING *)0; + int sawACL = 0; + int printedFull = 0; + + if (defMark == (STRING *)0) + defMark = AllocString(); + if (logDirectory == (STRING *)0) + logDirectory = AllocString(); + if (acInSave == (STRING *)0) + acInSave = AllocString(); + BuildString((char *)0, defMark); + BuildString((char *)0, acInSave); + BuildString((char *)0, logDirectory); + + iLine = 0; + while ((acIn = + (unsigned char *)ReadLine2(fp, acInSave, + &iLine)) != (unsigned char *)0) { + char *pcLine, *pcMode, *pcLog, *pcRem, *pcStart, *pcMark, *pcBreak; + char *pcColon; + + acStart = PruneSpace((char *)acIn); + if (acStart[0] == '#') { + printf("%s\n", acStart); + continue; + } + if (printedFull == 0) { + printf("default full {\n\trw *;\n}\n"); + printedFull = 1; + } + + if ('%' == acStart[0] && '%' == acStart[1] && '\000' == acStart[2]) { + break; + } + if ((char *)0 != (pcLine = strchr(acStart, '=')) && + ((char *)0 == (pcColon = strchr(acStart, ':')) || + pcColon > pcLine)) { + *pcLine++ = '\000'; + acStart = PruneSpace(acStart); + pcLine = PruneSpace(pcLine); + if (0 == strcmp(acStart, "LOGDIR")) { + BuildString((char *)0, logDirectory); + BuildString(pcLine, logDirectory); + printf("default * {\n"); + if (logDirectory->used > 1) + printf("\tlogfile %s/&;\n", logDirectory->string); + else + printf("\tlogfile \"\";\n"); + if (defMark->used > 1) + printf("\ttimestamp %s;\n", defMark->string); + else + printf("\ttimestamp \"\";\n"); + printf("\tinclude full;\n}\n"); + } else if (0 == strcmp(acStart, "TIMESTAMP")) { + BuildString((char *)0, defMark); + BuildString(pcLine, defMark); + printf("default * {\n"); + if (logDirectory->used > 1) + printf("\tlogfile %s/&;\n", logDirectory->string); + else + printf("\tlogfile \"\";\n"); + if (defMark->used > 1) + printf("\ttimestamp %s;\n", defMark->string); + else + printf("\ttimestamp \"\";\n"); + printf("\tinclude full;\n}\n"); + } else if (0 == strcmp(acStart, "DOMAINHACK")) { + } else if (0 == strncmp(acStart, "BREAK", 5) && + acStart[5] >= '1' && acStart[5] <= '9' && + acStart[6] == '\000') { + CONDDEBUG((1, "ReadCfg(): BREAK%c found with `%s'", + acStart[5], pcLine)); + if (pcLine[0] == '\000') { + printf("break %c {\n\tstring \"\";\n}\n", acStart[5]); + } else { + char *q, *p; + p = pcLine; + BuildTmpString((char *)0); + while ((q = strchr(p, '"')) != (char *)0) { + *q = '\000'; + BuildTmpString(p); + BuildTmpString("\\\""); + p = q + 1; + *q = '"'; + } + q = BuildTmpString(p); + printf("break %c {\n\tstring \"%s\";\n}\n", acStart[5], + q); + } + } else { + Error("%s(%d) unknown variable `%s'", pcFile, iLine, + acStart); + } + continue; + } + if ((char *)0 == (pcLine = strchr(acStart, ':')) || + (char *)0 == (pcMode = strchr(pcLine + 1, ':')) || + (char *)0 == (pcLog = strchr(pcMode + 1, ':'))) { + Error("%s(%d) bad config line `%s'", pcFile, iLine, acIn); + continue; + } + *pcLine++ = '\000'; + *pcMode++ = '\000'; + *pcLog++ = '\000'; + + acStart = PruneSpace(acStart); + pcLine = PruneSpace(pcLine); + pcMode = PruneSpace(pcMode); + pcLog = PruneSpace(pcLog); + + if ((char *)0 != (pcMark = strchr(pcLog, ':'))) { + *pcMark++ = '\000'; + pcLog = PruneSpace(pcLog); + pcMark = PruneSpace(pcMark); + /* Skip null intervals */ + if (pcMark[0] == '\000') + pcMark = (char *)0; + } + + if ((char *)0 == pcMark) { + pcBreak = (char *)0; + } else { + if ((char *)0 != (pcBreak = strchr(pcMark, ':'))) { + *pcBreak++ = '\000'; + pcMark = PruneSpace(pcMark); + pcBreak = PruneSpace(pcBreak); + /* Ignore null specs */ + if (pcMark[0] == '\000') + pcMark = (char *)0; + if (pcBreak[0] == '\000') + pcBreak = (char *)0; + } + } + + if ((char *)0 != (pcRem = strchr(pcLine, '@'))) { + *pcRem++ = '\000'; + pcLine = PruneSpace(pcLine); + pcRem = PruneSpace(pcRem); + } + + printf("console %s {\n", acStart); + if (pcRem == (char *)0) { + printf("\tmaster localhost;\n"); + } else { + printf("\tmaster %s;\n", pcRem); + } + + /* + * Here we substitute the console name for any '&' character in the + * logfile name. That way you can just have something like + * "/var/console/&" for each of the conserver.cf entries. + */ + if (pcLog[0] == '&' && pcLog[1] == '\000' && + logDirectory->used > 1) { + /* special case where logfile name is '&' and the LOGDIR was + * seen above. in this case we just allow inheritance to + * work it's magic. + */ + } else if (pcLog[0] == '\000') { + printf("\tlogfile \"\";\n"); + } else { + STRING *lfile; + lfile = AllocString(); + BuildString((char *)0, lfile); + pcStart = pcLog; + BuildString(pcStart, lfile); + if (logDirectory->used > 1 && lfile->used > 1 && + lfile->string[0] != '/') { + char *p; + BuildTmpString((char *)0); + p = BuildTmpString(lfile->string); + BuildString((char *)0, lfile); + BuildString(logDirectory->string, lfile); + BuildStringChar('/', lfile); + BuildString(p, lfile); + BuildTmpString((char *)0); + } + printf("\tlogfile %s;\n", lfile->string); + DestroyString(lfile); + } + + if (pcMark) { + printf("\ttimestamp %s;\n", pcMark); + } + + if (pcBreak) { + int bt; + bt = atoi(pcBreak); + if (bt > 9 || bt < 0) { + Error("%s(%d) bad break spec `%d'", pcFile, iLine, bt); + } else { + printf("\tbreak %d;\n", bt); + } + } + + if (pcLine[0] == '!') { + pcLine = PruneSpace(pcLine + 1); + printf("\ttype host;\n"); + printf("\thost %s;\n", pcLine); + printf("\tport %s;\n", pcMode); + } else if ('|' == pcLine[0]) { + pcLine = PruneSpace(pcLine + 1); + printf("\ttype exec;\n"); + if (pcLine == (char *)0 || pcLine[0] == '\000') + printf("\texec \"\";\n"); + else + printf("\texec %s;\n", pcLine); + } else { + char p, *t; + printf("\ttype device;\n"); + printf("\tdevice %s;\n", pcLine); + t = pcMode; + while (isdigit((int)(*t))) { + ++t; + } + p = *t; + *t = '\000'; + printf("\tbaud %s;\n", pcMode); + switch (p) { + case 'E': + case 'e': + t = "even"; + break; + case 'M': + case 'm': + t = "mark"; + break; + case 'N': + case 'n': + case 'P': + case 'p': + t = "none"; + break; + case 'O': + case 'o': + t = "odd"; + break; + case 'S': + case 's': + t = "space"; + break; + default: + Error + ("%s(%d) unknown parity type `%c' - assuming `none'", + pcFile, iLine, p); + t = "none"; + break; + } + printf("\tparity %s;\n", t); + } + printf("}\n"); + } + + while ((acIn = + (unsigned char *)ReadLine2(fp, acInSave, + &iLine)) != (unsigned char *)0) { + char *pcNext; + char cType; + + acStart = PruneSpace((char *)acIn); + if (acStart[0] == '#') { + printf("%s\n", acStart); + continue; + } + + if ('%' == acStart[0] && '%' == acStart[1] && '\000' == acStart[2]) { + break; + } + if ((char *)0 == (pcNext = strchr(acStart, ':'))) { + Error("%s(%d) missing colon?", pcFile, iLine); + continue; + } + + do { + *pcNext++ = '\000'; + } while (isspace((int)(*pcNext))); + + switch (acStart[0]) { + case 'a': /* allowed, allow, allows */ + case 'A': + if (!sawACL) { + sawACL = 1; + printf("access * {\n"); + } + printf("\tallowed %s;\n", pcNext); + break; + case 'r': /* rejected, refused, refuse */ + case 'R': + if (!sawACL) { + sawACL = 1; + printf("access * {\n"); + } + printf("\trejected %s;\n", pcNext); + break; + case 't': /* trust, trusted, trusts */ + case 'T': + if (!sawACL) { + sawACL = 1; + printf("access * {\n"); + } + printf("\ttrusted %s;\n", pcNext); + break; + default: + cType = ' '; + Error("%s(%d) unknown access key `%s'", pcFile, iLine, + acStart); + break; + } + } + if (sawACL) { + printf("}\n"); + } +} + +int +#if PROTOTYPES +main(int argc, char **argv) +#else +main(argc, argv) + int argc; + char **argv; +#endif +{ + char *pcFile; + FILE *fp; + + progname = "convert"; + fDebug = 0; + + + if (argc != 2) { + Error("Usage: convert old-conserver.cf"); + return 1; + } + + pcFile = argv[1]; + if ((fp = fopen(pcFile, "r")) == (FILE *)0) { + Error("fopen(%s): %s", pcFile, strerror(errno)); + return 1; + } + + ReadCfg(pcFile, fp); + return 0; +} diff --git a/conserver/fallback.c b/conserver/fallback.c index b302be4..ac4cc7b 100644 --- a/conserver/fallback.c +++ b/conserver/fallback.c @@ -1,5 +1,5 @@ /* - * $Id: fallback.c,v 5.53 2003-03-17 08:27:34-08 bryan Exp $ + * $Id: fallback.c,v 5.58 2003-08-15 08:18:26-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -14,78 +14,31 @@ * Mike Rowan (mtr@mace.cc.purdue.edu) */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include + #include -#if defined(_AIX) /* - * get a pty for the user (emulate the neato sequent call) (mm) + * get a pty for the user + * + * this has been revamped rather heavily for 8.0.0. i've taken ideas + * from the xemacs and openssh distributions to get code that *should* + * work on systems i have no access to. thanks to those reference + * packages, i think things are ok...hopefully it's true! */ static int #if PROTOTYPES -GetPseudoTTY(STRING * slave, STRING * master) +GetPseudoTTY(STRING *slave, int *slaveFD) #else -GetPseudoTTY(slave, master) +GetPseudoTTY(slave, slaveFD) STRING *slave; - STRING *master; + int *slaveFD; #endif { - int fd; - char *pcName; - - if (0 > (fd = open("/dev/ptc", O_RDWR | O_NDELAY, 0))) { - return -1; - } - if ((char *)0 == (pcName = ttyname(fd))) { - return -1; - } - BuildString((char *)0, slave); - BuildString(pcName, slave); - - BuildString((char *)0, master); - BuildString(pcName, master); - master->string[7] = 'c'; - - return fd; -} - -#else - -#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) -#if defined(linux) -extern char *ptsname(); -extern int grantpt(); -extern int unlockpt(); -#endif - -/* get a pty for the user -- emulate the neato sequent call under (gregf) - * DYNIX/ptx v4.0 - */ -static int -#if PROTOTYPES -GetPseudoTTY(STRING * slave, STRING * master) -#else -GetPseudoTTY(slave, master) - STRING *slave; - STRING *master; -#endif -{ - int fd; +#if HAVE_OPENPTY + int fd = -1; + int sfd = -1; + int opty = 0; char *pcName; #if HAVE_SIGACTION sigset_t oldmask, newmask; @@ -93,9 +46,6 @@ GetPseudoTTY(slave, master) extern RETSIGTYPE FlagReapVirt PARAMS((int)); #endif - if (0 > (fd = open("/dev/ptmx", O_RDWR, 0))) { - return -1; - } #if HAVE_SIGACTION sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); @@ -106,7 +56,7 @@ GetPseudoTTY(slave, master) SimpleSignal(SIGCHLD, SIG_DFL); #endif - grantpt(fd); /* change permission of slave */ + opty = openpty(&fd, &sfd, NULL, NULL, NULL); #if HAVE_SIGACTION if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) @@ -116,52 +66,121 @@ GetPseudoTTY(slave, master) SimpleSignal(SIGCHLD, FlagReapVirt); #endif - unlockpt(fd); /* unlock slave */ - BuildString((char *)0, master); - if ((char *)0 == (pcName = ttyname(fd))) { - BuildString("/dev/ptmx", master); - } else { - BuildString(pcName, master); + if (opty != 0) { + if (fd >= 0) + close(fd); + if (sfd >= 0) + close(sfd); + return -1; } + if ((char *)0 == (pcName = ttyname(sfd))) { + close(fd); + close(sfd); + return -1; + } + BuildString((char *)0, slave); + BuildString(pcName, slave); - if ((char *)0 == (pcName = ptsname(fd))) { + *slaveFD = sfd; + return fd; +#else +#if (HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT) || defined(_AIX) + int fd = -1; + int sfd = -1; + char *pcName; +#if HAVE_SIGACTION + sigset_t oldmask, newmask; +#else + extern RETSIGTYPE FlagReapVirt PARAMS((int)); +#endif + int c; + /* clone list and idea stolen from xemacs distribution */ + static char *clones[] = { + "/dev/ptmx", /* Various systems */ + "/dev/ptm/clone", /* HPUX */ + "/dev/ptc", /* AIX */ + "/dev/ptmx_bsd", /* Tru64 */ + (char *)0 + }; + + /* try to find the pty allocator */ + for (c = 0; clones[c] != (char *)0; c++) { + if ((fd = open(clones[c], O_RDWR, 0)) >= 0) + break; + } + if (fd < 0) + return -1; + +#if HAVE_SIGACTION + sigemptyset(&newmask); + sigaddset(&newmask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) + Error("GetPseudoTTY(): sigprocmask(SIG_BLOCK): %s", + strerror(errno)); +#else + SimpleSignal(SIGCHLD, SIG_DFL); +#endif + +#if HAVE_GRANTPT + grantpt(fd); /* change permission of slave */ +#endif + +#if HAVE_SIGACTION + if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) + Error("GetPseudoTTY(): sigprocmask(SIG_SETMASK): %s", + strerror(errno)); +#else + SimpleSignal(SIGCHLD, FlagReapVirt); +#endif + +#if HAVE_UNLOCKPT + unlockpt(fd); /* unlock slave */ +#endif + +#if defined(_AIX) + if ((pcName = ttyname(fd)) == (char *)0) { + close(fd); + return -1; + } +#else +# if HAVE_PTSNAME + if ((pcName = ptsname(fd)) == (char *)0) { + close(fd); + return -1; + } +# else + close(fd); + return -1; +# endif +#endif + + /* go ahead and open the slave */ + if ((sfd = open(pcName, O_RDWR, 0)) < 0) { + Error("GetPseudoTTY(): open(%s): %s", pcName, strerror(errno)); + close(fd); return -1; } BuildString((char *)0, slave); BuildString(pcName, slave); + *slaveFD = sfd; return fd; -} #else -/* - * Below is the string for finding /dev/ptyXX. For each architecture we - * leave some pty's world writable because we don't have source for - * everything that uses pty's. For the most part, we'll be trying to - * make /dev/ptyq* the "free" pty's. - */ - -/* all the world's a vax ;-) */ -static char charone[] = "prstuvwxyzPQRSTUVWq"; -static char chartwo[] = - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/* - * get a pty for the user (emulate the neato sequent call) (ksb) - */ -static int -#if PROTOTYPES -GetPseudoTTY(STRING * slave, STRING * master) -#else -GetPseudoTTY(slave, master) - STRING *slave; - STRING *master; -#endif -{ + /* + * Below is the string for finding /dev/ptyXX. For each architecture we + * leave some pty's world writable because we don't have source for + * everything that uses pty's. For the most part, we'll be trying to + * make /dev/ptyq* the "free" pty's. + */ + /* all the world's a vax ;-) */ + static char charone[] = "prstuvwxyzPQRSTUVWq"; + static char chartwo[] = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char acMaster[] = "/dev/ptyXX"; static char acSlave[] = "/dev/ttyXX"; static char *pcOne = charone, *pcTwo = chartwo; - int fd, iLoop, iIndex = sizeof("/dev/pty") - 1; + int fd, sfd, iLoop, iIndex = sizeof("/dev/pty") - 1; char *pcOld1; struct stat statBuf; @@ -203,41 +222,47 @@ GetPseudoTTY(slave, master) break; } - BuildString((char *)0, master); - BuildString(acMaster, master); + /* go ahead and open the slave */ + if ((sfd = open(acSlave, O_RDWR, 0)) < 0) { + Error("GetPseudoTTY(): open(%s): %s", acSlave, strerror(errno)); + close(fd); + return -1; + } + BuildString((char *)0, slave); BuildString(acSlave, slave); + + *slaveFD = sfd; return fd; +#endif /* (HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT) || defined(_AIX) */ +#endif /* HAVE_OPENPTY */ } -#endif -#endif /* _AIX */ /* - * get a Joe pty bacause the daemon is not with us, sadly. (ksb) + * get a pty using the GetPseudoTTY code above */ int #if PROTOTYPES -FallBack(STRING * pcSlave, STRING * pcMaster) +FallBack(char **slave, int *sfd) #else -FallBack(pcSlave, pcMaster) - STRING *pcSlave, *pcMaster; +FallBack(slave, sfd) + char **slave; + int *sfd; #endif { int fd; - static STRING *pcTSlave = (STRING *) 0; - static STRING *pcTMaster = (STRING *) 0; + static STRING *pcTSlave = (STRING *)0; - if (pcTSlave == (STRING *) 0) + if (pcTSlave == (STRING *)0) pcTSlave = AllocString(); - if (pcTMaster == (STRING *) 0) - pcTMaster = AllocString(); - if (-1 == (fd = GetPseudoTTY(pcTSlave, pcTMaster))) { + if ((fd = GetPseudoTTY(pcTSlave, sfd)) == -1) { return -1; } - BuildString((char *)0, pcSlave); - BuildString(pcTSlave->string, pcSlave); - BuildString((char *)0, pcMaster); - BuildString(pcTMaster->string, pcMaster); + if ((*slave) != (char *)0) + free(*slave); + if (((*slave) = strdup(pcTSlave->string)) + == (char *)0) + OutOfMem(); return fd; } diff --git a/conserver/group.c b/conserver/group.c index 55f225d..0dec17f 100644 --- a/conserver/group.c +++ b/conserver/group.c @@ -1,5 +1,5 @@ /* - * $Id: group.c,v 5.212 2003-04-07 18:47:50-07 bryan Exp $ + * $Id: group.c,v 5.248 2003-09-19 08:58:18-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -52,19 +52,8 @@ * 4. This notice may not be removed or altered. */ -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #if PROTOTYPES #include @@ -73,9 +62,7 @@ #endif #include -#include #include - #include #include #include @@ -84,25 +71,24 @@ #include #include -#if HAVE_POSIX_REGCOMP -#include -#endif #if HAVE_PAM #include #endif -#if defined(USE_LIBWRAP) -#include -#include -#endif /* flags that a signal has occurred */ -static sig_atomic_t fSawChldHUP = 0, fSawReUp = 0, fSawMark = - 0, fSawGoAway = 0, fSawReapVirt = 0, fSawChldUSR2 = 0; +static sig_atomic_t fSawChldHUP = 0, fSawReUp = 0, fSawGoAway = + 0, fSawReapVirt = 0, fSawChldUSR2 = 0; +static time_t nextMarkTime = (time_t)0; +static time_t nextReInitCheckTime = (time_t)0; +static time_t nextAutoUpTime = (time_t)0; +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION +static unsigned long dmallocMarkClientConnection = 0; +#endif void #if PROTOTYPES -SendClientsMsg(CONSENT * pCE, char *message) +SendClientsMsg(CONSENT *pCE, char *message) #else SendClientsMsg(pCE, message) CONSENT *pCE; @@ -111,11 +97,11 @@ SendClientsMsg(pCE, message) { CONSCLIENT *pCL; - if ((CONSENT *) 0 == pCE) { + if ((CONSENT *)0 == pCE) { return; } - for (pCL = pCE->pCLon; (CONSCLIENT *) 0 != pCL; pCL = pCL->pCLnext) { + for (pCL = pCE->pCLon; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLnext) { if (pCL->fcon) { FileWrite(pCL->fd, message, -1); } @@ -124,7 +110,42 @@ SendClientsMsg(pCE, message) void #if PROTOTYPES -SendAllClientsMsg(GRPENT * pGE, char *message) +SendCertainClientsMsg(GRPENT *pGE, char *who, char *message) +#else +SendCertainClientsMsg(pGE, who, message) + GRPENT *pGE; + char *who; + char *message; +#endif +{ + CONSCLIENT *pCL; + char *console = (char *)0; + + if ((GRPENT *)0 == pGE || who == (char *)0 || message == (char *)0) { + return; + } + + if ((console = strchr(who, '@')) != (char *)0) { + *console++ = '\000'; + if (*console == '\000') + console = (char *)0; + } + + for (pCL = pGE->pCLall; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLscan) { + if (pCL->fcon) { + if (*who != '\000' && strcmp(pCL->username->string, who) != 0) + continue; + if (console != (char *)0 && + strcmp(pCL->pCEto->server, console) != 0) + continue; + FileWrite(pCL->fd, message, -1); + } + } +} + +void +#if PROTOTYPES +SendAllClientsMsg(GRPENT *pGE, char *message) #else SendAllClientsMsg(pGE, message) GRPENT *pGE; @@ -133,11 +154,11 @@ SendAllClientsMsg(pGE, message) { CONSCLIENT *pCL; - if ((GRPENT *) 0 == pGE) { + if ((GRPENT *)0 == pGE) { return; } - for (pCL = pGE->pCLall; (CONSCLIENT *) 0 != pCL; pCL = pCL->pCLscan) { + for (pCL = pGE->pCLall; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLscan) { if (pCL->fcon) { FileWrite(pCL->fd, message, -1); } @@ -146,17 +167,18 @@ SendAllClientsMsg(pGE, message) void #if PROTOTYPES -DisconnectClient(GRPENT * pGE, CONSCLIENT * pCL, char *message) +DisconnectClient(GRPENT *pGE, CONSCLIENT *pCL, char *message, FLAG force) #else -DisconnectClient(pGE, pCL, message) +DisconnectClient(pGE, pCL, message, force) GRPENT *pGE; CONSCLIENT *pCL; char *message; + FLAG force; #endif { CONSENT *pCEServing; - if (pGE == (GRPENT *) 0 || pCL == (CONSCLIENT *) 0) { + if (pGE == (GRPENT *)0 || pCL == (CONSCLIENT *)0) { return; } @@ -164,19 +186,27 @@ DisconnectClient(pGE, pCL, message) FileWrite(pCL->fd, message, -1); } + if (force != FLAGTRUE && !FileBufEmpty(pCL->fd)) { + pCL->ioState = ISFLUSHING; + return; + } + /* log it, drop from select list, * close gap in table, etc, etc... */ pCEServing = pCL->pCEto; if (pGE->pCEctl != pCEServing) { - Msg("[%s] logout %s", pCEServing->server.string, pCL->acid.string); - } + Msg("[%s] logout %s", pCEServing->server, pCL->acid->string); + } else if (pCL->iState == S_NORMAL) + Verbose(" logout %s", pCL->acid->string); - if (fNoinit && pCEServing->pCLon->pCLnext == (CONSCLIENT *) 0) - ConsDown(pCEServing, &pGE->rinit, 0); + if (pCEServing->ondemand == FLAGTRUE && + pCEServing->pCLon->pCLnext == (CONSCLIENT *)0) + ConsDown(pCEServing, FLAGFALSE, FLAGFALSE); - FD_CLR(FileFDNum(pCL->fd), &pGE->rinit); + FD_CLR(FileFDNum(pCL->fd), &rinit); + FD_CLR(FileFDNum(pCL->fd), &winit); FileClose(&pCL->fd); /* mark as not writer, if he is @@ -185,7 +215,7 @@ DisconnectClient(pGE, pCL, message) if (pCL->fwr) { pCL->fwr = 0; pCL->fwantwr = 0; - TagLogfileAct(pCEServing, "%s detached", pCL->acid.string); + TagLogfileAct(pCEServing, "%s detached", pCL->acid->string); if (pCEServing->nolog) { pCEServing->nolog = 0; TagLogfile(pCEServing, "Console logging restored (logout)"); @@ -197,11 +227,11 @@ DisconnectClient(pGE, pCL, message) * lists (all clients, and this console) */ pCL->fcon = 0; - if ((CONSCLIENT *) 0 != pCL->pCLnext) { + if ((CONSCLIENT *)0 != pCL->pCLnext) { pCL->pCLnext->ppCLbnext = pCL->ppCLbnext; } *(pCL->ppCLbnext) = pCL->pCLnext; - if ((CONSCLIENT *) 0 != pCL->pCLscan) { + if ((CONSCLIENT *)0 != pCL->pCLscan) { pCL->pCLscan->ppCLbscan = pCL->ppCLbscan; } *(pCL->ppCLbscan) = pCL->pCLscan; @@ -213,11 +243,65 @@ DisconnectClient(pGE, pCL, message) */ pCL->pCLnext = pGE->pCLfree; pGE->pCLfree = pCL; +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION + CONDDEBUG((1, "DisconnectClient(): dmalloc / MarkClientConnection")); + dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); +#endif +} + +int +#if PROTOTYPES +DisconnectCertainClients(GRPENT *pGE, char *admin, char *who) +#else +DisconnectCertainClients(pGE, admin, who) + GRPENT *pGE; + char *admin; + char *who; +#endif +{ + CONSCLIENT *pCL; + char *console = (char *)0; + int count = 0; + char *msg = (char *)0; + + if ((GRPENT *)0 == pGE || who == (char *)0) { + return 0; + } + + if ((console = strchr(who, '@')) != (char *)0) { + *console++ = '\000'; + if (*console == '\000') + console = (char *)0; + } + + for (pCL = pGE->pCLall; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLscan) { + /* skip folks not connected to a console + * we check for 'fcon' in other code, but that skips users + * that are suspended as well, we don't want that here + */ + if (pGE->pCEctl == pCL->pCEto) + continue; + if (*who != '\000' && strcmp(pCL->username->string, who) != 0) + continue; + if (console != (char *)0 && + strcmp(pCL->pCEto->server, console) != 0) + continue; + if (msg == (char *)0) { + BuildTmpString((char *)0); + BuildTmpString("[-- Disconnected by admin `"); + BuildTmpString(admin); + msg = BuildTmpString("' --]\r\n"); + } + DisconnectClient(pGE, pCL, msg, FLAGFALSE); + count++; + } + + return count; } void #if PROTOTYPES -DisconnectAllClients(GRPENT * pGE, char *message) +DisconnectAllClients(GRPENT *pGE, char *message) #else DisconnectAllClients(pGE, message) GRPENT *pGE; @@ -226,34 +310,100 @@ DisconnectAllClients(pGE, message) { CONSCLIENT *pCL; - if ((GRPENT *) 0 == pGE) { + if ((GRPENT *)0 == pGE) { return; } - for (pCL = pGE->pCLall; (CONSCLIENT *) 0 != pCL; pCL = pCL->pCLscan) { - DisconnectClient(pGE, pCL, message); + for (pCL = pGE->pCLall; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLscan) { + DisconnectClient(pGE, pCL, message, FLAGTRUE); } } void #if PROTOTYPES -DestroyClient(CONSCLIENT * pCL) +DestroyClient(CONSCLIENT *pCL) #else DestroyClient(pCL) CONSCLIENT *pCL; #endif { - DestroyString(&pCL->acid); - DestroyString(&pCL->peername); - DestroyString(&pCL->accmd); - DestroyString(&pCL->msg); + if (pCL == (CONSCLIENT *)0) + return; + if (pCL->acid != (STRING *)0) + DestroyString(pCL->acid); + if (pCL->peername != (STRING *)0) + DestroyString(pCL->peername); + if (pCL->accmd != (STRING *)0) + DestroyString(pCL->accmd); + if (pCL->msg != (STRING *)0) + DestroyString(pCL->msg); + if (pCL->username != (STRING *)0) + DestroyString(pCL->username); FileClose(&pCL->fd); free(pCL); } void #if PROTOTYPES -DestroyConsent(GRPENT * pGE, CONSENT * pCE) +DestroyConsentUsers(CONSENTUSERS **cu) +#else +DestroyConsentUsers(cu) + CONSENTUSERS **cu; +#endif +{ + CONSENTUSERS *n = (CONSENTUSERS *)0; + + if (cu == (CONSENTUSERS **)0) + return; + + while ((*cu) != (CONSENTUSERS *)0) { + n = (*cu)->next; + free(*cu); + (*cu) = n; + } +} + +CONSENTUSERS * +#if PROTOTYPES +ConsentFindUser(CONSENTUSERS *pCU, char *id) +#else +ConsentFindUser(pCU, id) + CONSENTUSERS *pCU; + char *id; +#endif +{ + for (; pCU != (CONSENTUSERS *)0; pCU = pCU->next) { + if (strcmp(pCU->user->name, id) == 0) { + return pCU; + } + } + return pCU; +} + +/* check user permissions. return 0 for r/w, 1 for r/o, -1 for none */ +int +#if PROTOTYPES +ClientAccess(CONSENT *pCE, char *user) +#else +ClientAccess(pCE, user) + CONSENT *pCE; + char *user; +#endif +{ + if (ConsentFindUser(pCE->rw, user) != (CONSENTUSERS *)0 || + ConsentFindUser(pCE->rw, "*") != (CONSENTUSERS *)0) { + return 0; + } else { + if (ConsentFindUser(pCE->ro, user) != (CONSENTUSERS *)0 || + ConsentFindUser(pCE->ro, "*") != (CONSENTUSERS *)0) + return 1; + } + return -1; +} + +void +#if PROTOTYPES +DestroyConsent(GRPENT *pGE, CONSENT *pCE) #else DestroyConsent(pGE, pCE) GRPENT *pGE; @@ -262,17 +412,18 @@ DestroyConsent(pGE, pCE) { CONSCLIENT *pCL; CONSENT **ppCE; + NAMES *name; - if (pCE == (CONSENT *) 0) + if (pCE == (CONSENT *)0 || pGE == (GRPENT *)0) return; - Debug(1, "DestroyConsent(): destroying `%s'", pCE->server.string); + CONDDEBUG((1, "DestroyConsent(): destroying `%s'", pCE->server)); /* must loop using pCLall and pCLscan for the same reason as the * drop: code. this is basically the same set of code, but modified * since we know we're going to nuke the console itself. */ - for (pCL = pGE->pCLall; pCL != (CONSCLIENT *) 0; pCL = pCL->pCLscan) { + for (pCL = pGE->pCLall; pCL != (CONSCLIENT *)0; pCL = pCL->pCLscan) { if (pCL->pCEto != pCE) continue; if (pCL->fcon) { @@ -280,11 +431,12 @@ DestroyConsent(pGE, pCE) "[-- Conserver reconfigured - console has been (re)moved --]\r\n", -1); } - Msg("[%s] logout %s", pCE->server.string, pCL->acid.string); - FD_CLR(FileFDNum(pCL->fd), &pGE->rinit); + Msg("[%s] logout %s", pCE->server, pCL->acid->string); + FD_CLR(FileFDNum(pCL->fd), &rinit); + FD_CLR(FileFDNum(pCL->fd), &winit); FileClose(&pCL->fd); if (pCL->fwr) { - TagLogfileAct(pCE, "%s detached", pCL->acid.string); + TagLogfileAct(pCE, "%s detached", pCL->acid->string); if (pCE->nolog) { pCE->nolog = 0; TagLogfile(pCE, "Console logging restored (logout)"); @@ -293,11 +445,11 @@ DestroyConsent(pGE, pCE) /* mark as unconnected and remove from both * lists (all clients, and this console) */ - if ((CONSCLIENT *) 0 != pCL->pCLnext) { + if ((CONSCLIENT *)0 != pCL->pCLnext) { pCL->pCLnext->ppCLbnext = pCL->ppCLbnext; } *(pCL->ppCLbnext) = pCL->pCLnext; - if ((CONSCLIENT *) 0 != pCL->pCLscan) { + if ((CONSCLIENT *)0 != pCL->pCLscan) { pCL->pCLscan->ppCLbscan = pCL->ppCLbscan; } *(pCL->ppCLbscan) = pCL->pCLscan; @@ -306,9 +458,9 @@ DestroyConsent(pGE, pCE) pGE->pCLfree = pCL; } - ConsDown(pCE, &pGE->rinit, 0); + ConsDown(pCE, FLAGFALSE, FLAGTRUE); - for (ppCE = &(pGE->pCElist); *ppCE != (CONSENT *) 0; + for (ppCE = &(pGE->pCElist); *ppCE != (CONSENT *)0; ppCE = &((*ppCE)->pCEnext)) { if (*ppCE == pCE) { *ppCE = pCE->pCEnext; @@ -316,13 +468,33 @@ DestroyConsent(pGE, pCE) } } - DestroyString(&pCE->server); - DestroyString(&pCE->dfile); - DestroyString(&pCE->lfile); - DestroyString(&pCE->networkConsoleHost); - DestroyString(&pCE->acslave); - DestroyString(&pCE->pccmd); + DestroyConsentUsers(&(pCE->ro)); + DestroyConsentUsers(&(pCE->rw)); + + if (pCE->server != (char *)0) + free(pCE->server); + if (pCE->host != (char *)0) + free(pCE->host); + if (pCE->master != (char *)0) + free(pCE->master); + if (pCE->exec != (char *)0) + free(pCE->exec); + if (pCE->device != (char *)0) + free(pCE->device); + if (pCE->logfile != (char *)0) + free(pCE->logfile); + if (pCE->execSlave != (char *)0) + free(pCE->execSlave); + while (pCE->aliases != (NAMES *)0) { + name = pCE->aliases->next; + if (pCE->aliases->name != (char *)0) + free(pCE->aliases->name); + free(pCE->aliases); + pCE->aliases = name; + } FileClose(&pCE->fdlog); + if (pCE->wbuf != (STRING *)0) + DestroyString(pCE->wbuf); free(pCE); pGE->imembers--; @@ -330,7 +502,7 @@ DestroyConsent(pGE, pCE) void #if PROTOTYPES -DestroyGroup(GRPENT * pGE) +DestroyGroup(GRPENT *pGE) #else DestroyGroup(pGE) GRPENT *pGE; @@ -339,16 +511,16 @@ DestroyGroup(pGE) CONSENT *pCEtmp, *pCE; CONSCLIENT *pCLtmp, *pCL; - if (pGE == (GRPENT *) 0) + if (pGE == (GRPENT *)0) return; - Debug(1, "DestroyGroup(): destroying group #%d (%d members)", pGE->id, - pGE->imembers); + CONDDEBUG((1, "DestroyGroup(): destroying group #%d (%d members)", + pGE->id, pGE->imembers)); /* nuke each console (which kicks off clients) */ DestroyConsent(pGE, pGE->pCEctl); pCE = pGE->pCElist; - while (pCE != (CONSENT *) 0) { + while (pCE != (CONSENT *)0) { pCEtmp = pCE->pCEnext; DestroyConsent(pGE, pCE); pCE = pCEtmp; @@ -356,13 +528,13 @@ DestroyGroup(pGE) /* now we can nuke the client structures */ pCL = pGE->pCLall; - while (pCL != (CONSCLIENT *) 0) { + while (pCL != (CONSCLIENT *)0) { pCLtmp = pCL->pCLscan; DestroyClient(pCL); pCL = pCLtmp; } pCL = pGE->pCLfree; - while (pCL != (CONSCLIENT *) 0) { + while (pCL != (CONSCLIENT *)0) { pCLtmp = pCL->pCLnext; DestroyClient(pCL); pCL = pCLtmp; @@ -448,22 +620,22 @@ CheckPass(pcUser, pcWord) #if HAVE_PAM int pam_error; char *appdata[2]; - static pam_handle_t *pamh = (pam_handle_t *) 0; + static pam_handle_t *pamh = (pam_handle_t *)0; struct pam_conv conv; appdata[0] = pcUser; appdata[1] = pcWord; conv.conv = &QuietConv; conv.appdata_ptr = (void *)&appdata; - Debug(1, "CheckPass(): pam_start(conserver,%s,...)", pcUser); + CONDDEBUG((1, "CheckPass(): pam_start(conserver,%s,...)", pcUser)); pam_error = pam_start("conserver", pcUser, &conv, &pamh); if (pam_error == PAM_SUCCESS) { pam_set_item(pamh, PAM_RHOST, "IHaveNoIdeaHowIGotHere"); - Debug(1, "CheckPass(): pam_authenticate(%s)", pcUser); + CONDDEBUG((1, "CheckPass(): pam_authenticate(%s)", pcUser)); pam_error = pam_authenticate(pamh, PAM_SILENT); if (pam_error == PAM_SUCCESS) { - Debug(1, "CheckPass(): pam_acct_mgmt(%s)", pcUser); + CONDDEBUG((1, "CheckPass(): pam_acct_mgmt(%s)", pcUser)); pam_error = pam_acct_mgmt(pamh, PAM_SILENT); if (pam_error != PAM_SUCCESS) { Error("CheckPass(): PAM failure(%s): %s", pcUser, @@ -473,7 +645,7 @@ CheckPass(pcUser, pcWord) Error("CheckPass(): PAM failure(%s): %s", pcUser, pam_strerror(pamh, pam_error)); } - Debug(1, "CheckPass(): pam_end(%s)", pcUser); + CONDDEBUG((1, "CheckPass(): pam_end(%s)", pcUser)); pam_end(pamh, pam_error); if (pam_error == PAM_ABORT) /* things just got real bad */ fSawGoAway = 1; @@ -501,7 +673,8 @@ CheckPass(pcUser, pcWord) pcWord = ""; } if ((pwd = getpwnam(pcUser)) == (struct passwd *)0) { - Debug(1, "CheckPass(): getpwnam(%s): %s", pcUser, strerror(errno)); + CONDDEBUG((1, "CheckPass(): getpwnam(%s): %s", pcUser, + strerror(errno))); retval = AUTH_NOUSER; goto finished_pass; } @@ -509,10 +682,10 @@ CheckPass(pcUser, pcWord) #if HAVE_ISCOMSEC && HAVE_GETPRPWNAM if (iscomsec()) { - Debug(1, "CheckPass(): trusted password check"); + CONDDEBUG((1, "CheckPass(): trusted password check")); if ((prpwd = getprpwnam(pcUser)) == (struct pr_passwd *)0) { - Debug(1, "CheckPass(): getprpwnam(%s): %s", pcUser, - strerror(errno)); + CONDDEBUG((1, "CheckPass(): getprpwnam(%s): %s", pcUser, + strerror(errno))); retval = AUTH_NOUSER; goto finished_pass; } @@ -522,10 +695,10 @@ CheckPass(pcUser, pcWord) #if HAVE_GETSPNAM if ('x' == pass[0] && '\000' == pass[1]) { - Debug(1, "CheckPass(): shadow password check"); + CONDDEBUG((1, "CheckPass(): shadow password check")); if ((spwd = getspnam(pcUser)) == (struct spwd *)0) { - Debug(1, "CheckPass(): getspnam(%s): %s", pcUser, - strerror(errno)); + CONDDEBUG((1, "CheckPass(): getspnam(%s): %s", pcUser, + strerror(errno))); retval = AUTH_NOUSER; goto finished_pass; } @@ -551,7 +724,8 @@ CheckPass(pcUser, pcWord) #endif encrypted = crypt(pcWord, salt); if ((strcmp(pass, encrypted) != 0)) { - Debug(1, "CheckPass(): password check failed (%s)", pass); + CONDDEBUG((1, "CheckPass(): password check failed (%s)", + pass)); retval = AUTH_INVALID; } } @@ -604,9 +778,40 @@ FlagSawChldUSR2(sig) #endif } +void +#if PROTOTYPES +ConsoleError(CONSENT *pCE) +#else +ConsoleError(pCE) + CONSENT *pCE; +#endif +{ + /* If someone was writing, they fall back to read-only */ + if (pCE->pCLwr != (CONSCLIENT *)0) { + pCE->pCLwr->fwr = 0; + pCE->pCLwr->fwantwr = 1; + TagLogfileAct(pCE, "%s detached", pCE->pCLwr->acid->string); + pCE->pCLwr = (CONSCLIENT *)0; + } + + if (pCE->autoreinit != FLAGTRUE) { + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + } else { + /* Try an initial reconnect */ + Msg("[%s] automatic reinitialization", pCE->server); + ConsInit(pCE); + + /* If we didn't succeed, try again later */ + if (!pCE->fup) + pCE->autoReUp = 1; + else + pCE->pCLwr = FindWrite(pCE->pCLon); + } +} + static void #if PROTOTYPES -ReOpen(GRPENT * pGE) +ReOpen(GRPENT *pGE) #else ReOpen(pGE) GRPENT *pGE; @@ -614,21 +819,21 @@ ReOpen(pGE) { CONSENT *pCE; - if ((GRPENT *) 0 == pGE) { + if ((GRPENT *)0 == pGE) { return; } - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; pCE = pCE->pCEnext) { - if ((CONSFILE *) 0 == pCE->fdlog) { + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + if ((CONSFILE *)0 == pCE->fdlog) { continue; } FileClose(&pCE->fdlog); - if ((CONSFILE *) 0 == + if ((CONSFILE *)0 == (pCE->fdlog = - FileOpen(pCE->lfile.string, O_RDWR | O_CREAT | O_APPEND, - 0666))) { - Error("ReOpen(): cannot reopen log file `%s': %s", - pCE->lfile.string, strerror(errno)); + FileOpen(pCE->logfile, O_RDWR | O_CREAT | O_APPEND, 0666))) { + Error("[%s] FileOpen(%s): %s: forcing down", pCE->server, + pCE->logfile, strerror(errno)); + ConsoleError(pCE); continue; } } @@ -650,7 +855,7 @@ FlagReUp(sig) static void #if PROTOTYPES -ReUp(GRPENT * pGE, short automatic) +ReUp(GRPENT *pGE, short automatic) #else ReUp(pGE, automatic) GRPENT *pGE; @@ -659,80 +864,48 @@ ReUp(pGE, automatic) { CONSENT *pCE; int autoReUp; - static time_t lastup = (time_t) 0; /* last time we tried to up all downed */ - static time_t lastautoup = (time_t) 0; /* last time we tried to autoup */ + time_t tyme; - if ((GRPENT *) 0 == pGE) { + if ((GRPENT *)0 == pGE) return; - } - if ((automatic == 1) && ((time(NULL) - lastautoup) < 60)) + tyme = time((time_t *)0); + if ((automatic == 1) && (tyme < nextAutoUpTime)) return; if ((automatic == 2) && - (!fReopenall || ((time(NULL) - lastup) < (fReopenall * 60)))) + (!config->reinitcheck || (tyme < nextReInitCheckTime))) return; - ClearHostCache(); - - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; pCE = pCE->pCEnext) { - if (pCE->fup || fNoinit || (automatic == 1 && !pCE->autoReUp)) + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + if (pCE->fup || pCE->ondemand == FLAGTRUE || + (automatic == 1 && !pCE->autoReUp)) continue; autoReUp = pCE->autoReUp; if (automatic) - Msg("[%s] automatic reinitialization", pCE->server.string); - ConsInit(pCE, &pGE->rinit, 1); - if (pCE->fup) + Msg("[%s] automatic reinitialization", pCE->server); + ConsInit(pCE); + if (pCE->fup && pCE->ioState == ISNORMAL) pCE->pCLwr = FindWrite(pCE->pCLon); else if (automatic) pCE->autoReUp = autoReUp; } /* update all the timers */ - if (automatic == 0) - lastup = lastautoup = time(NULL); - else if (automatic == 1) - lastautoup = time(NULL); - else if (automatic == 2) - lastup = lastautoup = time(NULL); -} - -static RETSIGTYPE -#if PROTOTYPES -FlagMark(int sig) -#else -FlagMark(sig) - int sig; -#endif -{ - fSawMark = 1; -#if !HAVE_SIGACTION - SimpleSignal(SIGALRM, FlagMark); -#endif -} - -/* various areas of the code (sometimes not even our own) mess with - * the alarm signal, so this function is here to reset it to what - * we need. We do not actually set an alarm here, but set the flag - * that will call Mark() which will set the next alarm. - */ -void -#if PROTOTYPES -ResetMark(void) -#else -ResetMark() -#endif -{ - SimpleSignal(SIGALRM, FlagMark); - fSawMark = 1; + if (automatic == 0 || automatic == 2) { + if (config->reinitcheck) + nextReInitCheckTime = tyme + (config->reinitcheck * 60); + } + if (!fNoautoreup) + nextAutoUpTime = tyme + 60; } void #if PROTOTYPES -TagLogfile(const CONSENT * pCE, const char *fmt, ...) +TagLogfile(const CONSENT *pCE, char *fmt, ...) #else TagLogfile(pCE, fmt, va_alist) const CONSENT *pCE; - const char *fmt; + char *fmt; va_dcl #endif { @@ -743,22 +916,22 @@ TagLogfile(pCE, fmt, va_alist) va_start(ap); #endif - if ((pCE == (CONSENT *) 0) || (pCE->fdlog == (CONSFILE *) 0)) + if ((pCE == (CONSENT *)0) || (pCE->fdlog == (CONSFILE *)0)) return; FileWrite(pCE->fdlog, "[-- ", -1); FileVWrite(pCE->fdlog, fmt, ap); - FilePrint(pCE->fdlog, " -- %s]\r\n", StrTime(NULL)); + FilePrint(pCE->fdlog, " -- %s]\r\n", StrTime((time_t *)0)); va_end(ap); } void #if PROTOTYPES -TagLogfileAct(const CONSENT * pCE, const char *fmt, ...) +TagLogfileAct(const CONSENT *pCE, char *fmt, ...) #else TagLogfileAct(pCE, fmt, va_alist) const CONSENT *pCE; - const char *fmt; + char *fmt; va_dcl #endif { @@ -769,19 +942,19 @@ TagLogfileAct(pCE, fmt, va_alist) va_start(ap); #endif - if ((pCE == (CONSENT *) 0) || (pCE->fdlog == (CONSFILE *) 0) || - (pCE->activitylog == 0)) + if ((pCE == (CONSENT *)0) || (pCE->fdlog == (CONSFILE *)0) || + (pCE->activitylog != FLAGTRUE)) return; FileWrite(pCE->fdlog, "[-- ", -1); FileVWrite(pCE->fdlog, fmt, ap); - FilePrint(pCE->fdlog, " -- %s]\r\n", StrTime(NULL)); + FilePrint(pCE->fdlog, " -- %s]\r\n", StrTime((time_t *)0)); va_end(ap); } static void #if PROTOTYPES -Mark(GRPENT * pGE) +Mark(GRPENT *pGE) #else Mark(pGE) GRPENT *pGE; @@ -789,40 +962,40 @@ Mark(pGE) { char acOut[100]; /* MARK spec ~ 40 chars */ time_t tyme; - int i; CONSENT *pCE; - if ((GRPENT *) 0 == pGE) { + if ((GRPENT *)0 == pGE) { return; } /* [-- MARK -- `date`] */ sprintf(acOut, "[-- MARK -- %s]\r\n", StrTime(&tyme)); - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; pCE = pCE->pCEnext) { - if ((CONSFILE *) 0 == pCE->fdlog) { - continue; - } - if ((pCE->nextMark > 0) && (tyme >= pCE->nextMark)) { - Debug(1, "Mark(): [-- MARK --] stamp added to %s", - pCE->lfile.string); - FileWrite(pCE->fdlog, acOut, -1); - /* Add as many pCE->mark values as necessary so that we move - * beyond the current time. - */ - pCE->nextMark += - (((tyme - pCE->nextMark) / pCE->mark) + 1) * pCE->mark; + nextMarkTime = (time_t)0; + + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + if (pCE->nextMark > 0) { + if (tyme >= pCE->nextMark) { + if ((CONSFILE *)0 != pCE->fdlog) { + CONDDEBUG((1, "Mark(): [-- MARK --] stamp added to %s", + pCE->logfile)); + FileWrite(pCE->fdlog, acOut, -1); + } + /* Add as many pCE->mark values as necessary so that we move + * beyond the current time. + */ + pCE->nextMark += + (((tyme - pCE->nextMark) / pCE->mark) + 1) * pCE->mark; + } + if (nextMarkTime == (time_t)0 || nextMarkTime > pCE->nextMark) + nextMarkTime = pCE->nextMark; } } - if ((i = (60 - (tyme % 60))) <= 0) { - i = 1; - } - alarm(i); } void #if PROTOTYPES -WriteLog(CONSENT * pCE, char *s, int len) +WriteLog(CONSENT *pCE, char *s, int len) #else WriteLog(pCE, s, len) CONSENT *pCE; @@ -830,32 +1003,32 @@ WriteLog(pCE, s, len) int len; #endif { - char acOut[100]; /* [%s], time ~ 30 chars */ + char buf[100]; /* [%s], time ~ 30 chars */ int i = 0; int j; - if ((CONSFILE *) 0 == pCE->fdlog) { + if ((CONSFILE *)0 == pCE->fdlog) { return; } if (pCE->mark >= 0) { /* no line marking */ FileWrite(pCE->fdlog, s, len); return; } - acOut[0] = '\000'; + buf[0] = '\000'; for (j = 0; j < len; j++) { if (pCE->nextMark == 0) { FileWrite(pCE->fdlog, s + i, j - i); i = j; - if (acOut[0] == '\000') { - sprintf(acOut, "[%s]", StrTime(NULL)); + if (buf[0] == '\000') { + sprintf(buf, "[%s]", StrTime((time_t *)0)); } - FileWrite(pCE->fdlog, acOut, -1); + FileWrite(pCE->fdlog, buf, -1); pCE->nextMark = pCE->mark; } if (s[j] == '\n') { - Debug(1, - "WriteLog(): [%s] found newline (nextMark=%d, mark=%d)", - pCE->server.string, pCE->nextMark, pCE->mark); + CONDDEBUG((1, + "WriteLog(): [%s] found newline (nextMark=%d, mark=%d)", + pCE->server, pCE->nextMark, pCE->mark)); pCE->nextMark++; } } @@ -914,25 +1087,25 @@ FlagReapVirt(sig) */ static void #if PROTOTYPES -DeUtmp(GRPENT * pGE, CONSFILE * sfd) +DeUtmp(GRPENT *pGE, int sfd) #else DeUtmp(pGE, sfd) GRPENT *pGE; - CONSFILE *sfd; + int sfd; #endif { CONSENT *pCE; /* shut down the socket */ - FileClose(&sfd); + close(sfd); /* say Bye to all connections */ - if ((GRPENT *) 0 != pGE) { + if ((GRPENT *)0 != pGE) { DisconnectAllClients(pGE, "[-- Console server shutting down --]\r\n"); - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; pCE = pCE->pCEnext) { - ConsDown(pCE, &pGE->rinit, 0); + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + ConsDown(pCE, FLAGFALSE, FLAGTRUE); } } @@ -948,7 +1121,7 @@ DeUtmp(pGE, sfd) */ static void #if PROTOTYPES -ReapVirt(GRPENT * pGE) +ReapVirt(GRPENT *pGE) #else ReapVirt(pGE) GRPENT *pGE; @@ -968,36 +1141,35 @@ ReapVirt(pGE) continue; } - if ((GRPENT *) 0 == pGE) { + if ((GRPENT *)0 == pGE) { continue; } - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; pCE = pCE->pCEnext) { + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { if (pid != pCE->ipid) continue; if (WIFEXITED(UWbuf)) - Msg("[%s] exit(%d)", pCE->server.string, - WEXITSTATUS(UWbuf)); + Msg("[%s] exit(%d)", pCE->server, WEXITSTATUS(UWbuf)); if (WIFSIGNALED(UWbuf)) - Msg("[%s] signal(%d)", pCE->server.string, - WTERMSIG(UWbuf)); + Msg("[%s] signal(%d)", pCE->server, WTERMSIG(UWbuf)); /* If someone was writing, they fall back to read-only */ - if (pCE->pCLwr != (CONSCLIENT *) 0) { + if (pCE->pCLwr != (CONSCLIENT *)0) { pCE->pCLwr->fwr = 0; pCE->pCLwr->fwantwr = 1; - TagLogfileAct(pCE, "%s detached", pCE->pCLwr->acid.string); - pCE->pCLwr = (CONSCLIENT *) 0; + TagLogfileAct(pCE, "%s detached", + pCE->pCLwr->acid->string); + pCE->pCLwr = (CONSCLIENT *)0; } - if (fNoautoreup && + if (pCE->autoreinit != FLAGTRUE && !(WIFEXITED(UWbuf) && WEXITSTATUS(UWbuf) == 0)) { - ConsDown(pCE, &pGE->rinit, 0); + ConsDown(pCE, FLAGTRUE, FLAGFALSE); } else { /* Try an initial reconnect */ - Msg("[%s] automatic reinitialization", pCE->server.string); - ConsInit(pCE, &pGE->rinit, 0); + Msg("[%s] automatic reinitialization", pCE->server); + ConsInit(pCE); /* If we didn't succeed, try again later */ if (!pCE->fup) @@ -1015,41 +1187,27 @@ static char acStop[] = { /* buffer for OOB stop command */ int #if PROTOTYPES -CheckPasswd(CONSCLIENT * pCLServing, char *pw_string) +CheckPasswd(CONSCLIENT *pCL, char *pw_string) #else -CheckPasswd(pCLServing, pw_string) - CONSCLIENT *pCLServing; +CheckPasswd(pCL, pw_string) + CONSCLIENT *pCL; char *pw_string; #endif { FILE *fp; int iLine = 0; - char *server, *servers, *this_pw, *user; - static STRING *username = (STRING *) 0; + char *this_pw, *user; - if (username == (STRING *) 0) - username = AllocString(); - - BuildString((char *)0, username); - BuildString(pCLServing->acid.string, username); - if ((user = strchr(username->string, '@'))) - *user = '\000'; - - if ((fp = fopen(pcPasswd, "r")) == (FILE *) 0) { - Msg("CheckPasswd(): cannot open passwd file %s: %s", pcPasswd, - strerror(errno)); - - if (CheckPass("root", pw_string) == AUTH_SUCCESS) { - Msg("[%s] user %s authenticated via root passwd", - pCLServing->pCEwant->server.string, - pCLServing->acid.string); + if ((fp = fopen(config->passwdfile, "r")) == (FILE *)0) { + if (CheckPass(pCL->username->string, pw_string) == AUTH_SUCCESS) { + Verbose("user %s authenticated", pCL->acid->string); return AUTH_SUCCESS; } } else { char *wholeLine; - static STRING *saveLine = (STRING *) 0; + static STRING *saveLine = (STRING *)0; - if (saveLine == (STRING *) 0) + if (saveLine == (STRING *)0) saveLine = AllocString(); BuildString((char *)0, saveLine); @@ -1059,26 +1217,17 @@ CheckPasswd(pCLServing, pw_string) if (wholeLine[0] == '\000') continue; - if ((char *)0 == (this_pw = strchr(wholeLine, ':')) || - (char *)0 == (servers = strchr(this_pw + 1, ':'))) { + if ((char *)0 == (this_pw = strchr(wholeLine, ':'))) { Error("CheckPasswd(): %s(%d) bad password line `%s'", - pcPasswd, iLine, wholeLine); + config->passwdfile, iLine, wholeLine); continue; } *this_pw++ = '\000'; - *servers++ = '\000'; user = PruneSpace(wholeLine); this_pw = PruneSpace(this_pw); - servers = PruneSpace(servers); - - /* - printf - ("Got servers <%s> passwd <%s> user <%s>, want <%s>\n", - servers, this_pw, user, pCLServing->pCEwant->server.string); - */ if (strcmp(user, "*any*") != 0 && - strcmp(user, username->string) != 0) + strcmp(user, pCL->username->string) != 0) continue; /* If one is empty and the other isn't, instant failure */ @@ -1089,73 +1238,14 @@ CheckPasswd(pCLServing, pw_string) if ((*this_pw == '\000' && *pw_string == '\000') || ((strcmp(this_pw, "*passwd*") == - 0) ? (CheckPass(username->string, + 0) ? (CheckPass(pCL->username->string, pw_string) == AUTH_SUCCESS) : (strcmp(this_pw, crypt(pw_string, this_pw)) == 0))) { - server = strtok(servers, ", \t\n"); - while (server) { /* For each server */ - if (strcmp(server, "any") == 0) { - Verbose("[%s] user %s authenticated", - pCLServing->pCEwant->server.string, - pCLServing->acid.string); - fclose(fp); - return AUTH_SUCCESS; - } else { - char *p; - int status; - static STRING *tomatch = (STRING *) 0; -#if HAVE_POSIX_REGCOMP - regex_t re; -#endif - if (tomatch == (STRING *) 0) - tomatch = AllocString(); - BuildString((char *)0, tomatch); -#if HAVE_POSIX_REGCOMP - BuildStringChar('^', tomatch); - BuildString(server, tomatch); - BuildStringChar('$', tomatch); -#else - BuildString(server, tomatch); -#endif - p = pCLServing->pCEwant->server.string; - while (p != (char *)0) { -#if HAVE_POSIX_REGCOMP - if (regcomp - (&re, tomatch->string, - REG_NOSUB | REG_ICASE) - != 0) { - Error - ("CheckPasswd(): %s(%d) server name `%s' not a valid regular expression", - pcPasswd, iLine, server); - break; - } - status = regexec(&re, p, 0, NULL, 0); - regfree(&re); -#else - status = strcasecmp(tomatch->string, p); -#endif - if (status == 0) { - Verbose("[%s] user %s authenticated", - pCLServing->pCEwant->server.string, - pCLServing->acid.string); - fclose(fp); - return AUTH_SUCCESS; - } - if (domainHack) { - p = strchr(p, '.'); - if ((char *)0 == p) { - break; - } - ++p; - } else { - break; - } - } - } - server = strtok(NULL, ", \t\n"); - } + Verbose("user %s authenticated", pCL->acid->string); + fclose(fp); + return AUTH_SUCCESS; } break; } @@ -1194,69 +1284,51 @@ IdleTyme(tyme) void #if PROTOTYPES -PutConsole(CONSENT * pCEServing, unsigned char c) +PutConsole(CONSENT *pCEServing, unsigned char c, int quote) #else -PutConsole(pCEServing, c) +PutConsole(pCEServing, c, quote) CONSENT *pCEServing; unsigned char c; + int quote; #endif { - if (pCEServing->isNetworkConsole && (c == IAC)) - write(pCEServing->fdtty, &c, 1); - write(pCEServing->fdtty, &c, 1); -} - -void -#if PROTOTYPES -SendRealBreak(CONSCLIENT * pCLServing, CONSENT * pCEServing) -#else -SendRealBreak(pCLServing, pCEServing) - CONSCLIENT *pCLServing; - CONSENT *pCEServing; -#endif -{ - Debug(1, "SendRealBreak(): [%s] sending a break", - pCEServing->server.string); - if (pCEServing->isNetworkConsole) { - unsigned char haltseq[2]; - - haltseq[0] = IAC; - haltseq[1] = BREAK; - write(pCEServing->fdtty, haltseq, 2); - } else { -#if HAVE_TERMIO_H - if (-1 == ioctl(pCEServing->fdtty, TCSBRK, (char *)0)) { - FileWrite(pCLServing->fd, "failed]\r\n", -1); - return; - } -#else -# if HAVE_TCSENDBREAK - if (-1 == tcsendbreak(pCEServing->fdtty, 0)) { - FileWrite(pCLServing->fd, "failed]\r\n", -1); - return; - } -# else -# if HAVE_TERMIOS_H - if (-1 == ioctl(pCEServing->fdtty, TIOCSBRK, (char *)0)) { - FileWrite(pCLServing->fd, "failed]\r\n", -1); - return; - } - FileWrite(pCLServing->fd, "- ", -1); - usleep(999999); - ResetMark(); - if (-1 == ioctl(pCEServing->fdtty, TIOCCBRK, (char *)0)) { - FileWrite(pCLServing->fd, "failed]\r\n", -1); - return; - } -# endif -# endif -#endif + /* if we need to send an IAC char to a telnet-based port, quote + * the thing (which means send two to the port). but, since we're + * using IAC as a trigger for breaks and pauses, we have to load + * two into the buffer here and two below (so two get sent). + * + * if we're just sending a IAC character in the raw, the 'quote' + * flag will not be set and we'll put only two IAC chars into + * the buffer (below)...which will result in one to the port. + * + * we're also tracking the first IAC character in the buffer with + * the wbufIAC variable...that way we don't have to do a string + * search every time we flush this thing ('cause it should be + * rather infrequent to have an IAC char). + */ + if (quote && pCEServing->type == HOST && c == IAC) { + BuildStringChar((char)c, pCEServing->wbuf); + if (pCEServing->wbufIAC == 0) + pCEServing->wbufIAC = pCEServing->wbuf->used; + BuildStringChar((char)c, pCEServing->wbuf); } + /* if we're trying to send an IAC char, quote it in the buffer */ + if (quote && c == IAC) { + BuildStringChar((char)c, pCEServing->wbuf); + if (pCEServing->wbufIAC == 0) + pCEServing->wbufIAC = pCEServing->wbuf->used; + } + BuildStringChar((char)c, pCEServing->wbuf); + if (c == IAC && pCEServing->wbufIAC == 0) + pCEServing->wbufIAC = pCEServing->wbuf->used; + + CONDDEBUG((1, "PutConsole(): queued byte to console %s", + pCEServing->server)); } void #if PROTOTYPES -DoBreakWork(CONSCLIENT * pCLServing, CONSENT * pCEServing, short bt, +DoBreakWork(CONSCLIENT *pCLServing, CONSENT *pCEServing, short bt, short cleanup) #else DoBreakWork(pCLServing, pCEServing, bt, cleanup) @@ -1271,9 +1343,9 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) short cntrl; char oct[3]; short octs = -1; - static STRING *cleaned = (STRING *) 0; + static STRING *cleaned = (STRING *)0; - if (cleaned == (STRING *) 0) + if (cleaned == (STRING *)0) cleaned = AllocString(); BuildString((char *)0, cleaned); @@ -1286,16 +1358,16 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) return; } if (bt == 0) { - bt = pCEServing->breakType; + bt = pCEServing->breakNum; waszero = 1; } - if (bt == 0 || breakList[bt - 1].used <= 1) { + if (bt == 0 || breakList[bt - 1].seq->used <= 1) { if (!cleanup) FileWrite(pCLServing->fd, "undefined]\r\n", -1); return; } - p = breakList[bt - 1].string; + p = breakList[bt - 1].seq->string; backslash = 0; cntrl = 0; while ((s = (*p++)) != '\000') { @@ -1322,7 +1394,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) c = oct[0] - '0'; for (i = 1; i <= octs; i++) c = c * 8 + (oct[i] - '0'); - PutConsole(pCEServing, c); + PutConsole(pCEServing, c, 1); } } octs = -1; @@ -1333,7 +1405,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) if (cleanup) BuildString("\\\\", cleaned); else - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); backslash = 0; } else backslash = 1; @@ -1357,11 +1429,21 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) s = '\v'; else if (s == '^') s = '^'; - else if (s == 'z') { + else if (s == 'd') { + if (cleanup) + BuildString("\\d", cleaned); + else { + PutConsole(pCEServing, IAC, 0); + PutConsole(pCEServing, '0' + bt, 0); + } + s = '\000'; + } else if (s == 'z') { if (cleanup) BuildString("\\z", cleaned); - else - SendRealBreak(pCLServing, pCEServing); + else { + PutConsole(pCEServing, IAC, 0); + PutConsole(pCEServing, BREAK, 0); + } s = '\000'; } else if (s >= '0' && s <= '7') { if (++octs < 3) { @@ -1373,7 +1455,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) if (cleanup) BuildStringChar(o, cleaned); else - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); s = '\000'; } else if (octs > 2) { Error("octal number too large in BREAK%d sequence", @@ -1390,7 +1472,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) c = oct[0] - '0'; for (i = 1; i <= octs; i++) c = c * 8 + (oct[i] - '0'); - PutConsole(pCEServing, c); + PutConsole(pCEServing, c, 1); } octs = -1; } @@ -1400,7 +1482,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) BuildStringChar('\\', cleaned); BuildStringChar(o, cleaned); } else - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); } backslash = 0; continue; @@ -1411,7 +1493,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) BuildString("^^", cleaned); else { s = s & 0x1f; - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); } cntrl = 0; } else @@ -1424,7 +1506,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) BuildString("^?", cleaned); else { s = 0x7f; /* delete */ - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); } continue; } @@ -1433,7 +1515,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) BuildStringChar(s, cleaned); } else { s = s & 0x1f; - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); } cntrl = 0; continue; @@ -1441,7 +1523,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) if (cleanup) BuildStringChar(s, cleaned); else - PutConsole(pCEServing, s); + PutConsole(pCEServing, s, 1); } if (octs > 2) { @@ -1459,7 +1541,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) c = oct[0] - '0'; for (i = 1; i <= octs; i++) c = c * 8 + (oct[i] - '0'); - PutConsole(pCEServing, c); + PutConsole(pCEServing, c, 1); } } @@ -1469,17 +1551,17 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) Error("trailing circumflex ignored in BREAK%d sequence", bt); if (cleanup) { - BuildString((char *)0, &breakList[bt - 1]); - BuildString(cleaned->string, &breakList[bt - 1]); + BuildString((char *)0, breakList[bt - 1].seq); + BuildString(cleaned->string, breakList[bt - 1].seq); } else { FileWrite(pCLServing->fd, "sent]\r\n", -1); - if (pCEServing->breaklog) { + if (pCEServing->breaklog == FLAGTRUE) { if (waszero) { TagLogfile(pCEServing, "break #0(%d) sent -- `%s'", bt, - breakList[bt - 1].string); + breakList[bt - 1].seq->string); } else { TagLogfile(pCEServing, "break #%d sent -- `%s'", bt, - breakList[bt - 1].string); + breakList[bt - 1].seq->string); } } } @@ -1487,7 +1569,7 @@ DoBreakWork(pCLServing, pCEServing, bt, cleanup) void #if PROTOTYPES -SendBreak(CONSCLIENT * pCLServing, CONSENT * pCEServing, short bt) +SendBreak(CONSCLIENT *pCLServing, CONSENT *pCEServing, short bt) #else SendBreak(pCLServing, pCEServing, bt) CONSCLIENT *pCLServing; @@ -1506,64 +1588,1521 @@ CleanupBreak(bt) short bt; #endif { - DoBreakWork((CONSCLIENT *) 0, (CONSENT *) 0, bt, 1); + DoBreakWork((CONSCLIENT *)0, (CONSENT *)0, bt, 1); } #if HAVE_OPENSSL int #if PROTOTYPES -AttemptSSL(CONSCLIENT * pCL) +AttemptSSL(CONSCLIENT *pCL) #else AttemptSSL(pCL) CONSCLIENT *pCL; #endif { - int sflags, fdnum; + int fdnum; SSL *ssl; + int retval; fdnum = FileFDNum(pCL->fd); - if (ctx == (SSL_CTX *) 0) { + if (ctx == (SSL_CTX *)0) { Error("AttemptSSL(): WTF? The SSL context disappeared?!?!?"); Bye(EX_SOFTWARE); } if (!(ssl = SSL_new(ctx))) { - Error("AttemptSSL(): SSL_new() failed for client `%s' (fd %d)", - pCL->peername.string, fdnum); + Error("AttemptSSL(): SSL_new() failed for fd %d", fdnum); return 0; } FileSetSSL(pCL->fd, ssl); SSL_set_accept_state(ssl); SSL_set_fd(ssl, fdnum); - Debug(1, - "AttemptSSL(): setting socket to blocking for client `%s' (fd %d)", - pCL->peername.string, fdnum); - sflags = fcntl(fdnum, F_GETFL, 0); - if (sflags != -1) - fcntl(fdnum, F_SETFL, sflags & ~O_NONBLOCK); - Debug(1, "AttemptSSL(): about to SSL_accept() for client `%s' (fd %d)", - pCL->peername.string, fdnum); - if (SSL_accept(ssl) <= 0) { - Error("SSL negotiation failed for client `%s'", - pCL->peername.string); - ERR_print_errors_fp(stderr); - SSL_free(ssl); - if (sflags != -1) - fcntl(fdnum, F_SETFL, sflags); + + if ((retval = FileSSLAccept(pCL->fd)) < 0) { + Error("AttemptSSL(): FileSSLAccept() failed for fd %d", fdnum); return 0; - } - Debug(1, - "AttemptSSL(): returning socket to non-blocking for client `%s' (fd %d)", - pCL->peername.string, fdnum); - if (sflags != -1) - fcntl(fdnum, F_SETFL, sflags); - FileSetType(pCL->fd, SSLSocket); - if (fDebug) - Debug(1, "AttemptSSL(): SSL Connection: %s :: %s", - SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl)); + } else if (retval == 0) + pCL->ioState = INSSLACCEPT; return 1; } #endif +void +#if PROTOTYPES +CommandAttach(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandAttach(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSCLIENT *pCL; + + if (pGE->pCEctl == pCEServing) { + FileWrite(pCLServing->fd, "no -- on ctl]\r\n", -1); + } else if (!(pCEServing->fup && pCEServing->ioState == ISNORMAL)) { + FileWrite(pCLServing->fd, "line to host is down]\r\n", -1); + } else if (pCEServing->fronly) { + FileWrite(pCLServing->fd, "host is read-only]\r\n", -1); + } else if (pCLServing->fro) { + FileWrite(pCLServing->fd, "read-only]\r\n", -1); + } else if ((CONSCLIENT *)0 == (pCL = pCEServing->pCLwr)) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, "attached (nologging)]\r\n", -1); + } else { + FileWrite(pCLServing->fd, "attached]\r\n", -1); + } + TagLogfileAct(pCEServing, "%s attached", pCLServing->acid->string); + } else if (pCL == pCLServing) { + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, "ok (nologging)]\r\n", -1); + } else { + FileWrite(pCLServing->fd, "ok]\r\n", -1); + } + } else { + pCLServing->fwantwr = 1; + FilePrint(pCLServing->fd, "no, %s is attached]\r\n", + pCL->acid->string); + } +} + +void +#if PROTOTYPES +CommandChangeFlow(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandChangeFlow(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + struct termios sbuf; + int cofile; + + if (pCEServing->type != DEVICE && pCEServing->type != EXEC) + return; + cofile = FileFDNum(pCEServing->cofile); + if (-1 == tcgetattr(cofile, &sbuf)) { + FileWrite(pCLServing->fd, "failed]\r\n", -1); + return; + } + if (0 != (sbuf.c_iflag & IXON)) { + sbuf.c_iflag &= ~(IXON); + FileWrite(pCLServing->fd, "ixon OFF]\r\n", -1); + } else { + sbuf.c_iflag |= IXON; + FileWrite(pCLServing->fd, "ixon ON]\r\n", -1); + } + if (-1 == tcsetattr(cofile, TCSANOW, &sbuf)) { + FileWrite(pCLServing->fd, "failed]\r\n", -1); + return; + } +} + +void +#if PROTOTYPES +CommandDown(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandDown(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSCLIENT *pCL; + + if (pGE->pCEctl == pCEServing) { + FileWrite(pCLServing->fd, "no -- on ctl]\r\n", -1); + return; + } + if (!pCLServing->fwr && !pCEServing->fronly && !pCLServing->fro) { + FileWrite(pCLServing->fd, "attach to down line]\r\n", -1); + return; + } + if (!pCEServing->fup) { + FileWrite(pCLServing->fd, "ok]\r\n", -1); + return; + } + + pCLServing->fwr = 0; + pCEServing->pCLwr = (CONSCLIENT *)0; + TagLogfileAct(pCEServing, "%s detached", pCLServing->acid->string); + ConsDown(pCEServing, FLAGFALSE, FLAGFALSE); + FileWrite(pCLServing->fd, "line down]\r\n", -1); + + /* tell all who closed it */ + for (pCL = pCEServing->pCLon; (CONSCLIENT *)0 != pCL; + pCL = pCL->pCLnext) { + if (pCL == pCLServing) + continue; + if (pCL->fcon) { + FilePrint(pCL->fd, "[line down by %s]\r\n", + pCLServing->acid->string); + } + } +} + +void +#if PROTOTYPES +CommandExamine(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandExamine(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSENT *pCE; + unsigned char buf[BUFSIZ]; + + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + char *d = (char *)0; + char *b = (char *)0; + char p = '\000'; + switch (pCE->type) { + case EXEC: + d = pCE->execSlave; + b = "Local"; + p = ' '; + break; + case DEVICE: + d = pCE->device; + b = pCE->baud->acrate; + p = pCE->parity->key[0]; + break; + case HOST: + BuildTmpString((char *)0); + BuildTmpString(pCE->host); + sprintf((char *)buf, "/%hu", pCE->port); + d = BuildTmpString((char *) + buf); + b = "Netwk"; + p = ' '; + break; + case UNKNOWN: /* shut up gcc */ + break; + } + sprintf((char *)buf, " %-24.24s on %-32.32s at %6.6s%c\r\n", + pCE->server, d, b, p); + FileWrite(pCLServing->fd, (char *)buf, -1); + } +} + +void +#if PROTOTYPES +CommandForce(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandForce(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSCLIENT *pCL; + + if (pGE->pCEctl == pCEServing) { + FileWrite(pCLServing->fd, "no -- on ctl]\r\n", -1); + return; + } else if (pCLServing->fro) { + FileWrite(pCLServing->fd, "read-only]\r\n", -1); + return; + } else if (pCEServing->fronly) { + FileWrite(pCLServing->fd, "host is read-only]\r\n", -1); + return; + } else if (!(pCEServing->fup && pCEServing->ioState == ISNORMAL)) { + FileWrite(pCLServing->fd, "line to host is down]\r\n", -1); + return; + } + if ((CONSCLIENT *)0 != (pCL = pCEServing->pCLwr)) { + if (pCL == pCLServing) { + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, "ok (nologging)]\r\n", -1); + } else { + FileWrite(pCLServing->fd, "ok]\r\n", -1); + } + return; + } + pCL->fwr = 0; + pCL->fwantwr = 1; + if (pCEServing->nolog) { + FilePrint(pCLServing->fd, "bumped %s (nologging)]\r\n", + pCL->acid->string); + } else { + FilePrint(pCLServing->fd, "bumped %s]\r\n", pCL->acid->string); + } + FileWrite(pCL->fd, "\r\n[forced to `spy' mode by ", -1); + FileWrite(pCL->fd, pCLServing->acid->string, -1); + FileWrite(pCL->fd, "]\r\n", -1); + TagLogfileAct(pCEServing, "%s bumped %s", pCLServing->acid->string, + pCL->acid->string); + } else { + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, "attached (nologging)]\r\n", -1); + } else { + FileWrite(pCLServing->fd, "attached]\r\n", -1); + } + TagLogfileAct(pCEServing, "%s attached", pCLServing->acid->string); + } + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; +} + +void +#if PROTOTYPES +CommandGroup(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandGroup(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSCLIENT *pCL; + unsigned char buf[BUFSIZ]; + + /* we do not show the ctl console + * else we'd get the client always + */ + for (pCL = pGE->pCLall; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLscan) { + if (pGE->pCEctl == pCL->pCEto) + continue; + sprintf((char *)buf, " %-32.32s %c %-7.7s %6s ", pCL->acid->string, + pCL == pCLServing ? '*' : ' ', + pCL->fcon ? (pCL->fwr ? "attach" : "spy") : "stopped", + IdleTyme(tyme - pCL->typetym)); + FileWrite(pCLServing->fd, (char *)buf, -1); + FilePrint(pCLServing->fd, "%s\r\n", pCL->pCEto->server); + } +} + +void +#if PROTOTYPES +CommandHosts(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandHosts(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSENT *pCE; + unsigned char buf[BUFSIZ]; + + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + sprintf((char *)buf, " %-24.24s %c %-4.4s %-.40s\r\n", pCE->server, + pCE == pCEServing ? '*' : ' ', (pCE->fup && + pCE->ioState == + ISNORMAL) ? "up" : "down", + pCE->pCLwr ? pCE->pCLwr->acid->string : pCE-> + pCLon ? "" : ""); + FileWrite(pCLServing->fd, (char *)buf, -1); + } +} + +void +#if PROTOTYPES +CommandInfo(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandInfo(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSENT *pCE; + CONSCLIENT *pCL; + + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + int comma = 0; + char *s = (char *)0; + FilePrint(pCLServing->fd, "%s:%s,%lu,%hu:", pCE->server, + myHostname, (unsigned long)thepid, pGE->port); + switch (pCE->type) { + case EXEC: + FilePrint(pCLServing->fd, "|:%s,%lu,%s", + (pCE->exec != (char *)0 ? pCE->exec : "/bin/sh"), + (unsigned long)pCE->ipid, pCE->execSlave); + break; + case HOST: + FilePrint(pCLServing->fd, "!:%s,%hu", pCE->host, + pCE->port); + break; + case DEVICE: + FilePrint(pCLServing->fd, "/:%s,%s%c", pCE->device, + (pCE->baud ? pCE->baud->acrate : ""), + (pCE->parity ? pCE->parity->key[0] : ' ')); + break; + case UNKNOWN: /* shut up gcc */ + break; + } + FilePrint(pCLServing->fd, ",%d:", FileFDNum(pCE->cofile)); + if (pCE->pCLwr) { + FilePrint(pCLServing->fd, "w@%s@%ld", pCE->pCLwr->acid->string, + tyme - pCE->pCLwr->typetym); + comma = 1; + } + + for (pCL = pCE->pCLon; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLnext) { + if (pCL == pCE->pCLwr) + continue; + if (comma) + FilePrint(pCLServing->fd, ","); + if (pCL->fcon) + FilePrint(pCLServing->fd, "r@%s@%ld@%s", pCL->acid->string, + tyme - pCL->typetym, (pCL->fwantwr && + !pCL->fro) ? "rw" : "ro"); + else + FilePrint(pCLServing->fd, "s@%s@%ld@%s", pCL->acid->string, + tyme - pCL->typetym, (pCL->fwantwr && + !pCL->fro) ? "rw" : "ro"); + comma = 1; + } + + FilePrint(pCLServing->fd, ":%s:%s:%s,%s,%s,%s,%d,%d:%d:%s:", + ((pCE->fup && + pCE->ioState == ISNORMAL) ? "up" : "down"), + (pCE->fronly ? "ro" : "rw"), + (pCE->logfile == (char *)0 ? "" : pCE->logfile), + (pCE->nolog ? "nolog" : "log"), + (pCE->activitylog == FLAGTRUE ? "act" : "noact"), + (pCE->breaklog == FLAGTRUE ? "brk" : "nobrk"), pCE->mark, + (pCE->fdlog ? pCE->fdlog->fd : -1), pCE->breakNum, + (pCE->autoReUp ? "autoup" : "noautoup")); + if (pCE->aliases != (NAMES *)0) { + NAMES *n; + comma = 0; + for (n = pCE->aliases; n != (NAMES *)0; n = n->next) { + if (comma) + FilePrint(pCLServing->fd, ","); + FilePrint(pCLServing->fd, "%s", n->name); + comma = 1; + } + } + BuildTmpString((char *)0); + s = (char *)0; + if (pCE->hupcl == FLAGTRUE) + s = BuildTmpString(",hupcl"); + if (pCE->cstopb == FLAGTRUE) + s = BuildTmpString(",cstopb"); + if (pCE->ixon == FLAGTRUE) + s = BuildTmpString(",ixon"); + if (pCE->ixany == FLAGTRUE) + s = BuildTmpString(",ixany"); + if (pCE->ixoff == FLAGTRUE) + s = BuildTmpString(",ixoff"); + if (pCE->crtscts == FLAGTRUE) + s = BuildTmpString(",crtscts"); + if (pCE->ondemand == FLAGTRUE) + s = BuildTmpString(",ondemand"); + if (pCE->reinitoncc == FLAGTRUE) + s = BuildTmpString(",reinitoncc"); + if (pCE->striphigh == FLAGTRUE) + s = BuildTmpString(",striphigh"); + if (pCE->autoreinit == FLAGTRUE) + s = BuildTmpString(",autoreinit"); + if (pCE->unloved == FLAGTRUE) + s = BuildTmpString(",unloved"); + FilePrint(pCLServing->fd, ":"); + if (s != (char *)0) + FilePrint(pCLServing->fd, "%s", s + 1); + BuildTmpString((char *)0); + FilePrint(pCLServing->fd, "\r\n"); + } +} + +void +#if PROTOTYPES +CommandLogging(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandLogging(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + if (pCLServing->fwr) { + pCEServing->nolog = !pCEServing->nolog; + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, "logging off]\r\n", -1); + TagLogfile(pCEServing, "Console logging disabled by %s", + pCLServing->acid->string); + } else { + FileWrite(pCLServing->fd, "logging on]\r\n", -1); + TagLogfile(pCEServing, "Console logging restored by %s", + pCLServing->acid->string); + } + } else { + FilePrint(pCLServing->fd, "read-only]\r\n"); + } +} + +void +#if PROTOTYPES +CommandOpen(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandOpen(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSCLIENT *pCL; + + if (pGE->pCEctl == pCEServing) { + FileWrite(pCLServing->fd, "no -- on ctl]\r\n", -1); + return; + } + if (pCEServing->fup && !pCLServing->fwr) { + FileWrite(pCLServing->fd, "attach to reopen]\r\n", -1); + return; + } + /* with a close/re-open we might + * change fd's + */ + ConsInit(pCEServing); + if (!(pCEServing->fup && pCEServing->ioState == ISNORMAL)) { + FileWrite(pCLServing->fd, "line to host is down]\r\n", -1); + } else if (pCEServing->fronly) { + FileWrite(pCLServing->fd, "up read-only]\r\n", -1); + } else if ((CONSCLIENT *)0 == (pCL = pCEServing->pCLwr)) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + FileWrite(pCLServing->fd, "up -- attached]\r\n", -1); + TagLogfileAct(pCEServing, "%s attached", pCLServing->acid->string); + } else if (pCL == pCLServing) { + FileWrite(pCLServing->fd, "up]\r\n", -1); + TagLogfileAct(pCEServing, "%s attached", pCLServing->acid->string); + } else { + FilePrint(pCLServing->fd, "up, %s is attached]\r\n", + pCL->acid->string); + } +} + +void +#if PROTOTYPES +CommandWho(GRPENT *pGE, CONSCLIENT *pCLServing, CONSENT *pCEServing, + long tyme) +#else +CommandWho(pGE, pCLServing, pCEServing, tyme) + GRPENT *pGE; + CONSCLIENT *pCLServing; + CONSENT *pCEServing; + long tyme; +#endif +{ + CONSCLIENT *pCL; + unsigned char buf[BUFSIZ]; + + for (pCL = pCEServing->pCLon; (CONSCLIENT *)0 != pCL; + pCL = pCL->pCLnext) { + sprintf((char *)buf, " %-32.32s %c %-7.7s %6s %s\r\n", + pCL->acid->string, pCL == pCLServing ? '*' : ' ', + pCL->fcon ? (pCL->fwr ? "attach" : "spy") : "stopped", + IdleTyme(tyme - pCL->typetym), pCL->actym); + FileWrite(pCLServing->fd, (char *)buf, -1); + } +} + +void +#if PROTOTYPES +DoConsoleRead(CONSENT *pCEServing) +#else +DoConsoleRead(pCEServing) + CONSENT *pCEServing; +#endif +{ + unsigned char acIn[BUFSIZ], acInOrig[BUFSIZ]; + int nr, i; + CONSCLIENT *pCL; + + int cofile = FileFDNum(pCEServing->cofile); + + if (!pCEServing->fup) { + FD_CLR(cofile, &rinit); + FD_CLR(cofile, &winit); + return; + } + /* read terminal line */ + if ((nr = + FileRead(pCEServing->cofile, acInOrig, sizeof(acInOrig))) < 0) { + ConsoleError(pCEServing); + return; + } + CONDDEBUG((1, "DoConsoleRead(): read %d bytes from fd %d", nr, + cofile)); + + if (pCEServing->type == HOST) { + /* Do a little Telnet Protocol interpretation + * state = 0: normal + * = 1: Saw a IAC char + * = 2: Saw a DONT/DO/WONT/WILL command + * = 5: Saw a \r + */ + int new = 0, state; + state = pCEServing->telnetState; + for (i = 0; i < nr; ++i) { + if (state == 0 && acInOrig[i] == IAC) { + CONDDEBUG((1, "DoConsoleRead(): [%s] got telnet `IAC'", + pCEServing->server)); + state = 1; + } else if (state == 1 && acInOrig[i] != IAC) { + CONDDEBUG((1, "DoConsoleRead(): [%s] got telnet cmd `%u'", + pCEServing->server, acInOrig[i])); + if (acInOrig[i] == DONT || acInOrig[i] == DO || + acInOrig[i] == WILL || acInOrig[i] == WONT) + state = 2; + else + state = 0; + } else if (state == 2) { + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet option `%u'", + pCEServing->server, acInOrig[i])); + state = 0; + } else { + if (state == 5) { + state = 0; + if (acInOrig[i] == '\000') + continue; + } + if (acInOrig[i] == IAC) + CONDDEBUG((1, "DoConsoleRead(): [%s] quoted `IAC'", + pCEServing->server)); + if (pCEServing->striphigh == FLAGTRUE) + acIn[new++] = acInOrig[i] & 127; + else + acIn[new++] = acInOrig[i]; + if (acInOrig[i] == '\r') + state = 5; + else + state = 0; + } + } + pCEServing->telnetState = state; + nr = new; + } else { + for (i = 0; i < nr; ++i) { + if (pCEServing->striphigh == FLAGTRUE) + acIn[i] = acInOrig[i] & 127; + else + acIn[i] = acInOrig[i]; + } + } + if (nr == 0) + return; + + /* log it and write to all connections on this server + */ + if (!pCEServing->nolog) { + WriteLog(pCEServing, (char *)acIn, nr); + } + + /* output all console info nobody is attached + */ + if (pCEServing->pCLwr == (CONSCLIENT *)0 && + pCEServing->unloved == FLAGTRUE) { + /* run through the console ouptut, + * add each character to the output line + * drop and reset if we have too much + * or are at the end of a line (ksb) + */ + for (i = 0; i < nr; ++i) { + pCEServing->acline[pCEServing->iend++] = acIn[i]; + if (pCEServing->iend < sizeof(pCEServing->acline) && + '\n' != acIn[i]) { + continue; + } + write(1, pCEServing->server, strlen(pCEServing->server)); + write(1, ": ", 2); + write(1, pCEServing->acline, pCEServing->iend); + pCEServing->iend = 0; + } + } + + /* write console info to clients (not suspended) + */ + for (pCL = pCEServing->pCLon; (CONSCLIENT *)0 != pCL; + pCL = pCL->pCLnext) { + if (pCL->fcon) { + FileWrite(pCL->fd, (char *)acIn, nr); + } + } +} + +void +#if PROTOTYPES +DoClientRead(GRPENT *pGE, CONSCLIENT *pCLServing) +#else +DoClientRead(pGE, pCLServing) + GRPENT *pGE; + CONSCLIENT *pCLServing; +#endif +{ + struct termios sbuf; + CONSENT *pCEServing = pCLServing->pCEto; + CONSENT *pCE; + int nr, i; + unsigned char acIn[BUFSIZ], acInOrig[BUFSIZ]; + time_t tyme; + static STRING *bcast = (STRING *)0; + static STRING *acA1 = (STRING *)0; + static STRING *acA2 = (STRING *)0; + + if (bcast == (STRING *)0) + bcast = AllocString(); + if (acA1 == (STRING *)0) + acA1 = AllocString(); + if (acA2 == (STRING *)0) + acA2 = AllocString(); + + /* read connection */ + if ((nr = FileRead(pCLServing->fd, acIn, sizeof(acIn))) < 0) { + DisconnectClient(pGE, pCLServing, (char *)0, FLAGFALSE); + return; + } + if (nr == 0) + return; + + /* update last keystroke time + */ + pCLServing->typetym = tyme = time((time_t *)0); + + for (i = 0; i < nr; ++i) { + acInOrig[i] = acIn[i]; + if (pCEServing->striphigh == FLAGTRUE) { + acIn[i] &= 127; + } + } + + for (i = 0; i < nr; ++i) { + if (pGE->pCEctl == pCEServing) { + static char *pcArgs; + static char *pcCmd; + + if ('\n' != acIn[i]) { + BuildStringChar(acIn[i], pCLServing->accmd); + continue; + } + if ((pCLServing->accmd->used > 1) && + ('\r' == + pCLServing->accmd->string[pCLServing->accmd->used - 2])) { + pCLServing->accmd->string[pCLServing->accmd->used - 2] = + '\000'; + pCLServing->accmd->used--; + } + + /* process password here...before we corrupt accmd */ + if (pCLServing->iState == S_PASSWD) { + if (CheckPasswd(pCLServing, pCLServing->accmd->string) != + AUTH_SUCCESS) { + FileWrite(pCLServing->fd, "invalid password\r\n", -1); + BuildString((char *)0, pCLServing->accmd); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } + Verbose(" login %s", pCLServing->acid->string); + FileWrite(pCLServing->fd, "ok\r\n", -1); + pCLServing->iState = S_NORMAL; + BuildString((char *)0, pCLServing->accmd); + continue; + } + + if ((pcArgs = + strchr(pCLServing->accmd->string, ' ')) != (char *)0) { + *pcArgs++ = '\000'; + } + if (pcArgs != (char *)0) + pcArgs = PruneSpace(pcArgs); + pcCmd = PruneSpace(pCLServing->accmd->string); + + if (strcmp(pcCmd, "help") == 0) { + static char *apcHelp1[] = { + "exit disconnect\r\n", + "help this help message\r\n", + "login log in\r\n", +#if HAVE_OPENSSL + "ssl start ssl session\r\n", +#endif + (char *)0 + }; + static char *apcHelp2[] = { + "broadcast send broadcast message\r\n", + "call connect to given console\r\n", + "disconnect* disconnect the given user(s)\r\n", + "examine examine port and baud rates\r\n", + "exit disconnect\r\n", + "group show users in this group\r\n", + "help this help message\r\n", + "hosts show host status and user\r\n", + "info show console information\r\n", + "textmsg send a text message\r\n", + "* = requires admin privileges\r\n", + (char *)0 + }; + char **ppc; + for (ppc = + (pCLServing->iState == S_IDENT ? apcHelp1 : apcHelp2); + (char *)0 != *ppc; ++ppc) { + FileWrite(pCLServing->fd, *ppc, -1); + } + } else if (strcmp(pcCmd, "exit") == 0) { + FileWrite(pCLServing->fd, "goodbye\r\n", -1); + DisconnectClient(pGE, pCLServing, (char *)0, FLAGFALSE); + return; +#if HAVE_OPENSSL + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "ssl") == 0) { + FileWrite(pCLServing->fd, "ok\r\n", -1); + if (!AttemptSSL(pCLServing)) { + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } +#endif + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "login") == 0) { +#if HAVE_OPENSSL + if (config->sslrequired == FLAGTRUE && + FileGetType(pCLServing->fd) != SSLSocket) { + FileWrite(pCLServing->fd, "encryption required\r\n", + -1); + } else { +#endif + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, + "login requires argument\r\n", -1); + } else { + BuildString((char *)0, pCLServing->username); + BuildString((char *)0, pCLServing->acid); + BuildString(pcArgs, pCLServing->username); + BuildString(pcArgs, pCLServing->acid); + BuildStringChar('@', pCLServing->acid); + BuildString(pCLServing->peername->string, + pCLServing->acid); + if (pCLServing->caccess == 't' || + CheckPasswd(pCLServing, "") == AUTH_SUCCESS) { + pCLServing->iState = S_NORMAL; + Verbose(" login %s", + pCLServing->acid->string); + FileWrite(pCLServing->fd, "ok\r\n", -1); + } else { + FileWrite(pCLServing->fd, "passwd?\r\n", -1); + pCLServing->iState = S_PASSWD; + } + } +#if HAVE_OPENSSL + } +#endif + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "call") == 0) { + if (pcArgs == (char *)0) + FileWrite(pCLServing->fd, "call requires argument\r\n", + -1); + else { + /* try to move to the given console + * we assume all the right checks for ambiguity + * were already done by the master process, so + * the first match should be what the user wants + */ + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; + pCE = pCE->pCEnext) { + NAMES *n = (NAMES *)0; + if (strcasecmp(pcArgs, pCE->server) + == 0) { + pCLServing->pCEwant = pCE; + break; + } + for (n = pCE->aliases; n != (NAMES *)0; + n = n->next) { + if (strcasecmp(pcArgs, n->name) + == 0) { + pCLServing->pCEwant = pCE; + break; + } + } + if (n != (NAMES *)0) + break; + } + if (pCLServing->pCEwant == (CONSENT *)0) { + NAMES *n = (NAMES *)0; + int len = strlen(pcArgs); + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; + pCE = pCE->pCEnext) { + if (strncasecmp(pcArgs, pCE->server, len) == 0) { + pCLServing->pCEwant = pCE; + break; + } + for (n = pCE->aliases; n != (NAMES *)0; + n = n->next) { + if (strncasecmp(pcArgs, n->name, len) == 0) { + pCLServing->pCEwant = pCE; + break; + } + } + if (n != (NAMES *)0) + break; + } + } + + if (pCLServing->pCEwant == (CONSENT *)0) { + FilePrint(pCLServing->fd, + "%s: no such console\r\n", pcArgs); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } + + pCLServing->fro = + ClientAccess(pCLServing->pCEwant, + pCLServing->username->string); + if (pCLServing->fro == -1) { + FilePrint(pCLServing->fd, + "%s: permission denied\r\n", pcArgs); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } + + /* remove from current host */ + if ((CONSCLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = + pCLServing->ppCLbnext; + } + *(pCLServing->ppCLbnext) = pCLServing->pCLnext; + if (pCLServing->fwr) { + pCLServing->fwr = 0; + pCLServing->fwantwr = 0; + TagLogfileAct(pCEServing, "%s detached", + pCLServing->acid->string); + pCEServing->pCLwr = FindWrite(pCEServing->pCLon); + } + + /* inform operators of the change + */ + Verbose(" attach %s to %s", + pCLServing->acid->string, + pCLServing->pCEwant->server); + Msg("[%s] login %s", pCLServing->pCEwant->server, + pCLServing->acid->string); + + /* set new host and link into new host list + */ + pCEServing = pCLServing->pCEwant; + pCLServing->pCEto = pCEServing; + pCLServing->pCLnext = pCEServing->pCLon; + pCLServing->ppCLbnext = &pCEServing->pCLon; + if ((CONSCLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = + &pCLServing->pCLnext; + } + pCEServing->pCLon = pCLServing; + + /* try to reopen line if specified at server startup + */ + if ((pCEServing->ondemand == FLAGTRUE || + pCEServing->reinitoncc == FLAGTRUE) && + !pCEServing->fup) + ConsInit(pCEServing); + + /* try for attach on new console + */ + if (! + (pCEServing->fup && + pCEServing->ioState == ISNORMAL)) { + FileWrite(pCLServing->fd, + "[line to host is down]\r\n", -1); + } else if (pCEServing->fronly) { + FileWrite(pCLServing->fd, + "[host is read-only]\r\n", -1); + } else if (((CONSCLIENT *)0 == pCEServing->pCLwr) + && !pCLServing->fro) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + FileWrite(pCLServing->fd, "[attached]\r\n", -1); + /* this keeps the ops console neat */ + pCEServing->iend = 0; + TagLogfileAct(pCEServing, "%s attached", + pCLServing->acid->string); + } else { + FileWrite(pCLServing->fd, "[spy]\r\n", -1); + } + pCLServing->fcon = 1; + pCLServing->iState = S_NORMAL; + } + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "info") == 0) { + CommandInfo(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "examine") == 0) { + CommandExamine(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "group") == 0) { + CommandGroup(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "hosts") == 0) { + CommandHosts(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "broadcast") == 0) { + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, + "broadcast requires argument\r\n", -1); + } else { + BuildString((char *)0, bcast); + BuildStringChar('[', bcast); + BuildString(pCLServing->acid->string, bcast); + BuildString(": ", bcast); + BuildString(pcArgs, bcast); + BuildString("]\r\n", bcast); + SendAllClientsMsg(pGE, bcast->string); + FileWrite(pCLServing->fd, "ok\r\n", -1); + } + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "textmsg") == 0) { + char *pcMsg; + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, + "textmsg requires two arguments\r\n", -1); + } else { + if ((pcMsg = strchr(pcArgs, ' ')) != (char *)0) { + *pcMsg++ = '\000'; + } + if (pcMsg == (char *)0) { + FileWrite(pCLServing->fd, + "textmsg requires two arguments\r\n", + -1); + } else { + pcMsg = PruneSpace(pcMsg); + + BuildString((char *)0, bcast); + BuildStringChar('[', bcast); + BuildString(pCLServing->acid->string, bcast); + BuildString(": ", bcast); + BuildString(pcMsg, bcast); + BuildString("]\r\n", bcast); + + SendCertainClientsMsg(pGE, pcArgs, bcast->string); + FileWrite(pCLServing->fd, "ok\r\n", -1); + } + } + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "disconnect") == 0) { + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, + "disconnect requires argument\r\n", -1); + } else { + if (ConsentFindUser + (pADList, + pCLServing->username->string) != (CONSENTUSERS *)0 + || ConsentFindUser(pADList, + "*") != (CONSENTUSERS *)0) { + int num; + Verbose("disconnect command (of `%s') by %s", + pcArgs, pCLServing->acid->string); + num = + DisconnectCertainClients(pGE, + pCLServing->acid-> + string, pcArgs); + /* client expects this string to be formatted + * in this way only. + */ + FilePrint(pCLServing->fd, + "ok -- disconnected %d users\r\n", num); + } else + FileWrite(pCLServing->fd, + "unauthorized command\r\n", -1); + } + } else { + FileWrite(pCLServing->fd, "unknown command\r\n", -1); + } + BuildString((char *)0, pCLServing->accmd); + } else + switch (pCLServing->iState) { + case S_IDENT: + case S_PASSWD: + /* these are not used in this mode */ + break; + case S_BCAST: + /* gather message */ + if ('\r' != acIn[i]) { + if (acIn[i] == '\a' || + (acIn[i] >= ' ' && acIn[i] <= '~')) { + BuildStringChar(acIn[i], pCLServing->msg); + if (pGE->pCEctl != pCEServing) + FileWrite(pCLServing->fd, (char *)&acIn[i], + 1); + } else if ((acIn[i] == '\b' || acIn[i] == 0x7f) + && pCLServing->msg->used > 1) { + if (pCLServing->msg-> + string[pCLServing->msg->used - 2] != '\a' + && pGE->pCEctl != pCEServing) { + FileWrite(pCLServing->fd, "\b \b", 3); + } + pCLServing->msg->string[pCLServing->msg->used - + 2] = '\000'; + pCLServing->msg->used--; + } + continue; + } + FileWrite(pCLServing->fd, "]\r\n", 3); + BuildString((char *)0, bcast); + BuildStringChar('[', bcast); + BuildString(pCLServing->acid->string, bcast); + BuildString(": ", bcast); + BuildString(pCLServing->msg->string, bcast); + BuildString("]\r\n", bcast); + SendClientsMsg(pCEServing, bcast->string); + + BuildString((char *)0, pCLServing->msg); + pCLServing->iState = S_NORMAL; + continue; + + case S_QUOTE: /* send octal code */ + /* must type in 3 octal digits */ + if (acIn[i] >= '0' && acIn[i] <= '7') { + BuildStringChar(acIn[i], pCLServing->accmd); + if (pCLServing->accmd->used < 4) { + FileWrite(pCLServing->fd, (char *)&acIn[i], 1); + continue; + } + FileWrite(pCLServing->fd, (char *)&acIn[i], 1); + FileWrite(pCLServing->fd, "]", 1); + + pCLServing->accmd->string[0] = + (((pCLServing->accmd->string[0] - '0') * 8 + + (pCLServing->accmd->string[1] - '0')) * 8) + + (pCLServing->accmd->string[2] - '0'); + PutConsole(pCEServing, + pCLServing->accmd->string[0], 1); + BuildString((char *)0, pCLServing->accmd); + } else { + FileWrite(pCLServing->fd, " aborted]\r\n", -1); + } + pCLServing->iState = S_NORMAL; + continue; + + case S_SUSP: + if (! + (pCEServing->fup && + pCEServing->ioState == ISNORMAL)) { + FileWrite(pCLServing->fd, " -- line down]\r\n", + -1); + } else if (pCEServing->fronly) { + FileWrite(pCLServing->fd, " -- read-only]\r\n", + -1); + } else if (((CONSCLIENT *)0 == pCEServing->pCLwr) + && !pCLServing->fro) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, + " -- attached (nologging)]\r\n", -1); + } else { + FileWrite(pCLServing->fd, " -- attached]\r\n", + -1); + } + TagLogfileAct(pCEServing, "%s attached", + pCLServing->acid->string); + } else { + FileWrite(pCLServing->fd, " -- spy mode]\r\n", -1); + } + pCLServing->fcon = 1; + pCLServing->iState = S_NORMAL; + continue; + + case S_NORMAL: + /* if it is an escape sequence shift states + */ + if (acInOrig[i] == pCLServing->ic[0]) { + pCLServing->iState = S_ESC1; + continue; + } + /* if we can write, write to slave tty + */ + if (pCLServing->fwr) { + PutConsole(pCEServing, acIn[i], 1); + continue; + } + /* if the client is stuck in spy mode + * give them a clue as to how to get out + * (LLL nice to put chars out as ^Ec, rather + * than octal escapes, but....) + */ + if ('\r' == acIn[i] || '\n' == acIn[i]) { + FilePrint(pCLServing->fd, + "[read-only -- use %s %s ? for help]\r\n", + FmtCtl(pCLServing->ic[0], acA1), + FmtCtl(pCLServing->ic[1], acA2)); + } + continue; + + case S_HALT1: /* halt sequence? */ + pCLServing->iState = S_NORMAL; + if (acIn[i] != '?' && (acIn[i] < '0' || acIn[i] > '9')) { + FileWrite(pCLServing->fd, "aborted]\r\n", -1); + continue; + } + + if (acIn[i] == '?') { + int i; + char ms[4]; + FileWrite(pCLServing->fd, "list]\r\n", -1); + i = pCEServing->breakNum; + if (i == 0 || breakList[i - 1].seq->used <= 1) + FileWrite(pCLServing->fd, + " 0 - 0ms, \r\n", -1); + else { + sprintf(ms, "%3d", breakList[i - 1].delay); + FilePrint(pCLServing->fd, + " 0 - %sms, `%s'\r\n", ms, + breakList[i - 1].seq->string); + } + for (i = 0; i < 9; i++) { + if (breakList[i].seq->used > 1) { + sprintf(ms, "%3d", breakList[i].delay); + FilePrint(pCLServing->fd, + " %d - %sms, `%s'\r\n", i + 1, + ms, breakList[i].seq->string); + } + } + } else { + int bt = acIn[i] - '0'; + SendBreak(pCLServing, pCEServing, bt); + } + continue; + + case S_CATTN: /* redef escape sequence? */ + pCLServing->ic[0] = acInOrig[i]; + FmtCtl(acInOrig[i], acA1); + FilePrint(pCLServing->fd, "%s ", acA1->string); + pCLServing->iState = S_CESC; + continue; + + case S_CESC: /* escape sequent 2 */ + pCLServing->ic[1] = acInOrig[i]; + pCLServing->iState = S_NORMAL; + FmtCtl(acInOrig[i], acA1); + FilePrint(pCLServing->fd, "%s ok]\r\n", acA1->string); + continue; + + case S_ESC1: /* first char in escape sequence */ + if (acInOrig[i] == pCLServing->ic[1]) { + if (pCLServing->fecho) + FileWrite(pCLServing->fd, "\r\n[", -1); + else + FileWrite(pCLServing->fd, "[", -1); + pCLServing->iState = S_CMD; + continue; + } + /* ^E^Ec or ^_^_^[ + * pass (possibly stripped) first ^E (^_) and + * stay in same state + */ + if (acInOrig[i] == pCLServing->ic[0]) { + if (pCLServing->fwr) { + PutConsole(pCEServing, acIn[i], 1); + } + continue; + } + /* ^Ex or ^_x + * pass both characters to slave tty (possibly stripped) + */ + pCLServing->iState = S_NORMAL; + if (pCLServing->fwr) { + char c = pCLServing->ic[0]; + if (pCEServing->striphigh == FLAGTRUE) + c = c & 127; + PutConsole(pCEServing, c, 1); + PutConsole(pCEServing, acIn[i], 1); + } + continue; + + case S_CMD: /* have 1/2 of the escape sequence */ + pCLServing->iState = S_NORMAL; + switch (acIn[i]) { + case '+': + case '-': + if (0 != (pCLServing->fecho = '+' == acIn[i])) + FileWrite(pCLServing->fd, "drop line]\r\n", + -1); + else + FileWrite(pCLServing->fd, + "no drop line]\r\n", -1); + break; + + case 'b': /* broadcast message */ + case 'B': + FileWrite(pCLServing->fd, "Enter message: ", + -1); + pCLServing->iState = S_BCAST; + break; + + case 'a': /* attach */ + case 'A': + CommandAttach(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'c': + case 'C': + CommandChangeFlow(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'd': /* down a console */ + case 'D': + CommandDown(pGE, pCLServing, pCEServing, tyme); + break; + + case 'e': /* redefine escape keys */ + case 'E': + pCLServing->iState = S_CATTN; + FileWrite(pCLServing->fd, "redef: ", -1); + break; + + case 'f': /* force attach */ + case 'F': + CommandForce(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'g': /* group info */ + case 'G': + FilePrint(pCLServing->fd, "group %s]\r\n", + pGE->pCEctl->server); + CommandGroup(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'P': /* DEC vt100 pf1 */ + case 'h': /* help */ + case 'H': + case '?': + HelpUser(pCLServing); + break; + + case 'i': + case 'I': + FileWrite(pCLServing->fd, "info]\r\n", -1); + CommandInfo(pGE, pCLServing, pCEServing, tyme); + break; + + case 'L': + CommandLogging(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'l': /* halt character 1 */ + if (pCEServing->fronly) { + FileWrite(pCLServing->fd, + "can't halt read-only host]\r\n", + -1); + continue; + } + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, + "attach to halt]\r\n", -1); + continue; + } + pCLServing->iState = S_HALT1; + FileWrite(pCLServing->fd, "halt ", -1); + break; + + case 'o': /* close and re-open line */ + case 'O': + CommandOpen(pGE, pCLServing, pCEServing, tyme); + break; + + case '\022': /* ^R */ + FileWrite(pCLServing->fd, "^R]\r\n", -1); + Replay(pCEServing->fdlog, pCLServing->fd, 1); + break; + + case 'R': /* DEC vt100 pf3 */ + case 'r': /* replay 20 lines */ + FileWrite(pCLServing->fd, "replay]\r\n", -1); + Replay(pCEServing->fdlog, pCLServing->fd, 20); + break; + + case 'p': /* replay 60 lines */ + FileWrite(pCLServing->fd, "long replay]\r\n", + -1); + Replay(pCEServing->fdlog, pCLServing->fd, 60); + break; + + case 'S': /* DEC vt100 pf4 */ + case 's': /* spy mode */ + pCLServing->fwantwr = 0; + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, "ok]\r\n", -1); + break; + } + pCLServing->fwr = 0; + TagLogfileAct(pCEServing, "%s detached", + pCLServing->acid->string); + pCEServing->pCLwr = + FindWrite(pCEServing->pCLon); + FileWrite(pCLServing->fd, "spying]\r\n", -1); + break; + + case 'u': /* hosts on server this */ + case 'U': + FileWrite(pCLServing->fd, "hosts]\r\n", -1); + CommandHosts(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'v': /* version */ + case 'V': + FilePrint(pCLServing->fd, "version `%s']\r\n", + THIS_VERSION); + break; + + case 'w': /* who */ + case 'W': + FilePrint(pCLServing->fd, "who %s]\r\n", + pCEServing->server); + CommandWho(pGE, pCLServing, pCEServing, tyme); + break; + + case 'x': + case 'X': + FileWrite(pCLServing->fd, "examine]\r\n", -1); + CommandExamine(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'z': /* suspend the client */ + case 'Z': + case '\032': + if (1 != + FileSend(pCLServing->fd, acStop, 1, + MSG_OOB)) { + break; + } + pCLServing->fcon = 0; + pCLServing->iState = S_SUSP; + if (pCEServing->pCLwr == pCLServing) { + pCLServing->fwr = 0; + pCLServing->fwantwr = 0; + pCEServing->pCLwr = (CONSCLIENT *)0; + TagLogfileAct(pCEServing, "%s detached", + pCLServing->acid->string); + } + break; + + case '\t': /* toggle tab expand */ + FileWrite(pCLServing->fd, "tabs]\r\n", -1); + if (-1 == + tcgetattr(FileFDNum(pCEServing->cofile), + &sbuf)) { + FileWrite(pCLServing->fd, "failed]\r\n", + -1); + continue; + } +# if !defined(XTABS) /* XXX hack */ +# define XTABS TAB3 +# endif + if (XTABS == (TABDLY & sbuf.c_oflag)) { + sbuf.c_oflag &= ~TABDLY; + sbuf.c_oflag |= TAB0; + } else { + sbuf.c_oflag &= ~TABDLY; + sbuf.c_oflag |= XTABS; + } + if (-1 == + tcsetattr(FileFDNum(pCEServing->cofile), + TCSANOW, &sbuf)) { + FileWrite(pCLServing->fd, "failed]\r\n", + -1); + continue; + } + break; + + case 'Q': /* DEC vt100 PF2 */ + case '.': /* disconnect */ + case '\004': + case '\003': + FileWrite(pCLServing->fd, "disconnect]\r\n", + -1); + nr = 0; + if (!pCEServing->fup || + pCEServing->type != DEVICE) { + DisconnectClient(pGE, pCLServing, + (char *)0, FLAGFALSE); + continue; + } + if (-1 == + tcgetattr(FileFDNum(pCEServing->cofile), + &sbuf)) { + FileWrite(pCLServing->fd, "[failed]\r\n", + -1); + continue; + } + if (0 == (sbuf.c_iflag & IXOFF)) { + sbuf.c_iflag |= IXOFF | IXON; + tcsetattr(FileFDNum(pCEServing->cofile), + TCSANOW, &sbuf); + } + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + continue; + + case ' ': /* abort escape sequence */ + case '\n': + case '\r': + FileWrite(pCLServing->fd, "ignored]\r\n", -1); + break; + + case '\\': /* quote mode (send ^Q,^S) */ + if (pCEServing->fronly) { + FileWrite(pCLServing->fd, + "can't write to read-only host]\r\n", + -1); + continue; + } + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, + "attach to send character]\r\n", + -1); + continue; + } + BuildString((char *)0, pCLServing->accmd); + pCLServing->iState = S_QUOTE; + FileWrite(pCLServing->fd, "quote \\", -1); + break; + + default: /* unknown sequence */ + FileWrite(pCLServing->fd, + "unknown -- use `?']\r\n", -1); + break; + } + continue; + } + } +} + /* routine used by the child processes. (ksb/fine) * Most of it is escape sequence parsing. @@ -1595,77 +3134,50 @@ AttemptSSL(pCL) */ static void #if PROTOTYPES -Kiddie(GRPENT * pGE, CONSFILE * sfd) +Kiddie(GRPENT *pGE, int sfd) #else Kiddie(pGE, sfd) GRPENT *pGE; - CONSFILE *sfd; + int sfd; #endif { CONSCLIENT *pCL, /* console we must scan/notify */ *pCLServing; /* client we are serving */ - CONSENT *pCEServing, /* console we are talking to */ - *pCE; /* the base of our console list */ + CONSENT *pCEServing; /* console we are talking to */ GRPENT *pGEtmp; REMOTE *pRCtmp; - int i, nr; - struct hostent *hpPeer; + int ret; time_t tyme; + time_t tymer; int fd; - char cType; - int maxfd; socklen_t so; fd_set rmask; - unsigned char acOut[BUFSIZ], acIn[BUFSIZ], acInOrig[BUFSIZ]; - static STRING *bcast = (STRING *) 0; - static STRING *acA1 = (STRING *) 0; - static STRING *acA2 = (STRING *) 0; -#if HAVE_TERMIOS_H - struct termios sbuf; -#else -# if HAVE_SGTTY_H - struct sgttyb sty; -# endif -#endif -#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - unsigned long dmallocMarkClientConnection = 0; -#endif + fd_set wmask; + unsigned char acOut[32]; + struct timeval tv; + struct timeval *tvp; - if (bcast == (STRING *) 0) - bcast = AllocString(); - if (acA1 == (STRING *) 0) - acA1 = AllocString(); - if (acA2 == (STRING *) 0) - acA2 = AllocString(); - /* nuke the other group lists - of no use in the child */ - while (pGroups != (GRPENT *) 0) { + while (pGroups != (GRPENT *)0) { pGEtmp = pGroups->pGEnext; if (pGroups != pGE) DestroyGroup(pGroups); pGroups = pGEtmp; } pGroups = pGE; - pGE->pGEnext = (GRPENT *) 0; + pGE->pGEnext = (GRPENT *)0; /* nuke the remote consoles - of no use in the child */ - while (pRCList != (REMOTE *) 0) { + while (pRCList != (REMOTE *)0) { pRCtmp = pRCList->pRCnext; - DestroyString(&pRCList->rserver); - DestroyString(&pRCList->rhost); - free(pRCList); + DestroyRemoteConsole(pRCList); pRCList = pRCtmp; } - pGE->pCEctl = (CONSENT *) calloc(1, sizeof(CONSENT)); - if (pGE->pCEctl == (CONSENT *) 0) + if ((pGE->pCEctl = (CONSENT *)calloc(1, sizeof(CONSENT))) + == (CONSENT *)0) OutOfMem(); - InitString(&pGE->pCEctl->server); - InitString(&pGE->pCEctl->dfile); - InitString(&pGE->pCEctl->lfile); - InitString(&pGE->pCEctl->networkConsoleHost); - InitString(&pGE->pCEctl->acslave); /* turn off signals that master() might have turned on * (only matters if respawned) @@ -1686,20 +3198,9 @@ Kiddie(pGE, sfd) SimpleSignal(SIGINT, FlagGoAwayAlso); sprintf((char *)acOut, "ctl_%hu", pGE->port); - BuildString((char *)acOut, &pGE->pCEctl->server); - pGE->pCEctl->iend = 0; - BuildString((char *)0, &pGE->pCEctl->lfile); - BuildString("/dev/null", &pGE->pCEctl->lfile); - BuildString((char *)0, &pGE->pCEctl->dfile); - BuildString("/dev/null", &pGE->pCEctl->dfile); - /* below "" gets us the default parity and baud structs - */ - pGE->pCEctl->pbaud = FindBaud(""); - pGE->pCEctl->pparity = FindParity(""); - pGE->pCEctl->fdlog = (CONSFILE *) 0; - pGE->pCEctl->fdtty = pGE->pCEctl->ipid = -1; - pGE->pCEctl->fup = 0; - pGE->pCEctl->pCLon = pGE->pCEctl->pCLwr = (CONSCLIENT *) 0; + if ((pGE->pCEctl->server = strdup((char *)acOut)) + == (char *)0) + OutOfMem(); /* set up stuff for the select() call once, then just copy it * rinit is all the fd's we might get data on, we copy it @@ -1707,20 +3208,27 @@ Kiddie(pGE, sfd) * we used to do in the loop, but we have to mod rinit whenever * we add a connection or drop one... (ksb) */ - maxfd = GetMaxFiles(); - FD_ZERO(&pGE->rinit); - FD_SET(FileFDNum(sfd), &pGE->rinit); + /*maxfd = GetMaxFiles(); */ + FD_ZERO(&rinit); + FD_ZERO(&winit); + FD_SET(sfd, &rinit); + if (maxfd < sfd + 1) + maxfd = sfd + 1; /* open all the files we need for the consoles in our group * if we can't get one (bitch and) flag as down */ - if (!fNoinit) - ReUp(pGE, 0); + ReUp(pGE, 0); /* prime the list of free connection slots */ - pGE->pCLfree = (CONSCLIENT *) calloc(1, sizeof(CONSCLIENT)); - if ((CONSCLIENT *) 0 == pGE->pCLfree) + if ((pGE->pCLfree = (CONSCLIENT *)calloc(1, sizeof(CONSCLIENT))) + == (CONSCLIENT *)0) OutOfMem(); + pGE->pCLfree->acid = AllocString(); + pGE->pCLfree->username = AllocString(); + pGE->pCLfree->peername = AllocString(); + pGE->pCLfree->accmd = AllocString(); + pGE->pCLfree->msg = AllocString(); /* on a SIGHUP we should close and reopen our log files and * reread the config file @@ -1734,12 +3242,12 @@ Kiddie(pGE, sfd) /* on a SIGUSR1 we try to bring up all downed consoles */ SimpleSignal(SIGUSR1, FlagReUp); - /* on a SIGALRM we should mark log files */ - ResetMark(); + /* prime the pump */ + Mark(pGE); /* the MAIN loop a group server */ - pGE->pCLall = (CONSCLIENT *) 0; + pGE->pCLall = (CONSCLIENT *)0; while (1) { /* check signal flags */ if (fSawGoAway) { @@ -1753,9 +3261,8 @@ Kiddie(pGE, sfd) if (fSawChldHUP) { fSawChldHUP = 0; ReopenLogfile(); - ReReadCfg(); + ReReadCfg(sfd); pGE = pGroups; - FD_SET(FileFDNum(sfd), &pGE->rinit); ReOpen(pGE); ReUp(pGE, 0); } @@ -1768,9 +3275,8 @@ Kiddie(pGE, sfd) if (fSawChldHUP) { fSawChldHUP = 0; ReopenLogfile(); - ReReadCfg(); + ReReadCfg(sfd); pGE = pGroups; - FD_SET(FileFDNum(sfd), &pGE->rinit); ReOpen(pGE); ReUp(pGE, 0); } @@ -1778,1338 +3284,465 @@ Kiddie(pGE, sfd) fSawReUp = 0; ReUp(pGE, 0); } - /* see if we need to bring things back up - this has to happen - * *before* ReUp(,1) otherwise we get double-reups */ - ReUp(pGE, 2); - if (fSawMark) { - fSawMark = 0; - Mark(pGE); - ReUp(pGE, 1); + + /* check for timeouts with consoles -bryan */ + tymer = (time_t)0; + tyme = time((time_t *)0); + for (pCEServing = pGE->pCElist; pCEServing != (CONSENT *)0; + pCEServing = pCEServing->pCEnext) { + if (pCEServing->stateTimer != (time_t)0 && + (tymer == (time_t)0 || tymer > pCEServing->stateTimer)) + tymer = pCEServing->stateTimer; + if (pCEServing->stateTimer > tyme) + continue; + pCEServing->stateTimer = (time_t)0; + if (pCEServing->ioState != INCONNECT) + continue; + Error("[%s] connect timeout: forcing down", + pCEServing->server); + /* can't use ConsoleError() here otherwise we could reinit + * the console repeatedly (immediately). we know there are + * no clients attached, so it's basically the same. + */ + ConsDown(pCEServing, FLAGTRUE, FLAGTRUE); } - rmask = pGE->rinit; + /* see if we need to bring things back up or mark logfiles + * or do other such events here. we call time() each time + * in case one of the subroutines actually takes a long time + * to complete */ + if (nextMarkTime != (time_t)0 && time((time_t *)0) >= nextMarkTime) + Mark(pGE); + if (nextReInitCheckTime != (time_t)0 && + time((time_t *)0) >= nextReInitCheckTime) + ReUp(pGE, 2); + /* must do ReUp(,1) last for timers to work right */ + if (nextAutoUpTime != (time_t)0 && + time((time_t *)0) >= nextAutoUpTime) + ReUp(pGE, 1); - if (-1 == - select(maxfd, &rmask, (fd_set *) 0, (fd_set *) 0, - (struct timeval *)0)) { + /* check on various timers and set the appropriate timeout */ + /* all this so we don't have to use alarm() any more... */ + + /* look for the nearest time */ + if (nextMarkTime != (time_t)0 && + (tymer == (time_t)0 || tymer > nextMarkTime)) + tymer = nextMarkTime; + if (nextReInitCheckTime != (time_t)0 && + (tymer == (time_t)0 || tymer > nextReInitCheckTime)) + tymer = nextReInitCheckTime; + if (nextAutoUpTime != (time_t)0 && + (tymer == (time_t)0 || tymer > nextAutoUpTime)) + tymer = nextAutoUpTime; + /* if we have a timer, figure out the delay left */ + if (tymer != (time_t)0) { + tyme = time((time_t *)0); + if (tymer > tyme) /* in the future */ + tv.tv_sec = tymer - tyme; + else /* now or in the past */ + tv.tv_sec = 1; + tv.tv_usec = 0; + tvp = &tv; + } else /* no timeout */ + tvp = (struct timeval *)0; + if (tvp == (struct timeval *)0) { + CONDDEBUG((1, "Kiddie(): no select timeout")); + } else { + CONDDEBUG((1, "Kiddie(): select timeout of %d seconds", + tv.tv_sec)); + } + + rmask = rinit; + wmask = winit; + + if ((ret = select(maxfd, &rmask, &wmask, (fd_set *)0, tvp)) == -1) { if (errno != EINTR) { Error("Kiddie(): select(): %s", strerror(errno)); + break; } continue; } - /* anything from any console? - */ - for (pCEServing = pGE->pCElist; pCEServing != (CONSENT *) 0; + if (ret == 0) /* timeout -- loop back up and handle it */ + continue; + + /* anything on a console? */ + for (pCEServing = pGE->pCElist; pCEServing != (CONSENT *)0; pCEServing = pCEServing->pCEnext) { - if (!pCEServing->fup || !FD_ISSET(pCEServing->fdtty, &rmask)) { + if (!pCEServing->fup) continue; - } - /* read terminal line */ - if ((nr = - read(pCEServing->fdtty, acInOrig, - sizeof(acInOrig))) <= 0) { - /* carrier lost */ - Error("[%s] lost carrier (%s)", pCEServing->server.string, - pCEServing->fvirtual ? pCEServing->acslave. - string : pCEServing->dfile.string); - - /* If someone was writing, they fall back to read-only */ - if (pCEServing->pCLwr != (CONSCLIENT *) 0) { - pCEServing->pCLwr->fwr = 0; - pCEServing->pCLwr->fwantwr = 1; - TagLogfileAct(pCEServing, "%s detached", - pCEServing->pCLwr->acid.string); - pCEServing->pCLwr = (CONSCLIENT *) 0; - } - - if (fNoautoreup) { - ConsDown(pCEServing, &pGE->rinit, 1); - } else { - /* Try an initial reconnect */ - Msg("[%s] automatic reinitialization", - pCEServing->server.string); - ConsInit(pCEServing, &pGE->rinit, 0); - - /* If we didn't succeed, try again later */ - if (!pCEServing->fup) - pCEServing->autoReUp = 1; - else - pCEServing->pCLwr = FindWrite(pCEServing->pCLon); - } - - continue; - } - Debug(1, "Kiddie(): read %d bytes from fd %d", nr, - pCEServing->fdtty); - - if (pCEServing->isNetworkConsole) { - /* Do a little Telnet Protocol interpretation - * state = 0: normal - * = 1: Saw a IAC char - * = 2: Saw a DONT/DO/WONT/WILL command - * = 5: Saw a \r - */ - int new = 0, state; - state = pCEServing->telnetState; - for (i = 0; i < nr; ++i) { - if (state == 0 && acInOrig[i] == IAC) { - Debug(1, "Kiddie(): [%s] got telnet `IAC'", - pCEServing->server.string); - state = 1; - } else if (state == 1 && acInOrig[i] != IAC) { - Debug(1, "Kiddie(): [%s] got telnet cmd `%u'", - pCEServing->server.string, acInOrig[i]); - if (acInOrig[i] == DONT || acInOrig[i] == DO || - acInOrig[i] == WILL || acInOrig[i] == WONT) - state = 2; - else - state = 0; - } else if (state == 2) { - Debug(1, "Kiddie(): [%s] got telnet option `%u'", - pCEServing->server.string, acInOrig[i]); - state = 0; - } else { - if (state == 5) { - state = 0; - if (acInOrig[i] == '\000') - continue; + switch (pCEServing->ioState) { + case INCONNECT: + /* deal with this state above as well */ + if (FileCanRead(pCEServing->cofile, &rmask, &wmask)) { + socklen_t slen; + int flags = 0; + int cofile = FileFDNum(pCEServing->cofile); + slen = sizeof(flags); + /* So, getsockopt seems to return -1 if there is + * something interesting in SO_ERROR under + * solaris...sheesh. So, the error message has + * the small change it's not accurate. + */ + if (getsockopt + (cofile, SOL_SOCKET, SO_ERROR, (char *)&flags, + &slen) < 0) { + Error + ("[%s] getsockopt(%u,SO_ERROR): %s: forcing down", + pCEServing->server, cofile, + strerror(errno)); + /* no ConsoleError() for same reason as above */ + ConsDown(pCEServing, FLAGTRUE, FLAGTRUE); + break; } - if (acInOrig[i] == IAC) - Debug(1, "Kiddie(): [%s] quoted `IAC'", - pCEServing->server.string); - if (fStrip) - acIn[new++] = acInOrig[i] & 127; - else - acIn[new++] = acInOrig[i]; - if (acInOrig[i] == '\r') - state = 5; - else - state = 0; + if (flags != 0) { + Error("[%s] connect(%u): %s: forcing down", + pCEServing->server, cofile, + strerror(flags)); + /* no ConsoleError() for same reason as above */ + ConsDown(pCEServing, FLAGTRUE, FLAGTRUE); + break; + } + pCEServing->ioState = ISNORMAL; } - } - pCEServing->telnetState = state; - nr = new; - } else { - for (i = 0; i < nr; ++i) { - if (fStrip) - acIn[i] = acInOrig[i] & 127; - else - acIn[i] = acInOrig[i]; - } - } - if (nr == 0) - continue; - - /* log it and write to all connections on this server - */ - if (!pCEServing->nolog) { - WriteLog(pCEServing, (char *)acIn, nr); - } - - /* output all console info nobody is attached - */ - if (fAll && (CONSCLIENT *) 0 == pCEServing->pCLwr) { - /* run through the console ouptut, - * add each character to the output line - * drop and reset if we have too much - * or are at the end of a line (ksb) - */ - for (i = 0; i < nr; ++i) { - pCEServing->acline[pCEServing->iend++] = acIn[i]; - if (pCEServing->iend < sizeof(pCEServing->acline) && - '\n' != acIn[i]) { - continue; + break; + case ISNORMAL: + if (FileCanRead(pCEServing->cofile, &rmask, &wmask)) + DoConsoleRead(pCEServing); + /* fall through to ISFLUSHING for buffered data */ + case ISFLUSHING: + /* write cofile data */ + if (!FileBufEmpty(pCEServing->cofile) && + FileCanWrite(pCEServing->cofile, &rmask, &wmask)) { + CONDDEBUG((1, "Master(): flushing fd %d", + FileFDNum(pCEServing->cofile))); + if (FileWrite(pCEServing->cofile, (char *)0, 0) < + 0) { + ConsoleError(pCEServing); + break; + } } - if (pCEServing->server.used > 1) - write(1, pCEServing->server.string, - pCEServing->server.used - 1); - write(1, ": ", 2); - write(1, pCEServing->acline, pCEServing->iend); - pCEServing->iend = 0; - } - } - - /* write console info to clients (not suspended) - */ - for (pCL = pCEServing->pCLon; (CONSCLIENT *) 0 != pCL; - pCL = pCL->pCLnext) { - if (pCL->fcon) { - FileWrite(pCL->fd, (char *)acIn, nr); - } + /* write fdlog data */ + if (!FileBufEmpty(pCEServing->fdlog) && + FileCanWrite(pCEServing->fdlog, &rmask, &wmask)) { + CONDDEBUG((1, "Kiddie(): flushing fd %d", + FileFDNum(pCEServing->fdlog))); + if (FileWrite(pCEServing->fdlog, (char *)0, 0) < 0) { + ConsoleError(pCEServing); + break; + } + } + /* stop if we're in ISFLUSHING state and out of data */ + if ((pCEServing->ioState == ISFLUSHING) && + FileBufEmpty(pCEServing->cofile) && + FileBufEmpty(pCEServing->fdlog)) + /* no ConsoleError() for same reason as above */ + ConsDown(pCEServing, FLAGFALSE, FLAGTRUE); + break; + default: + /* this really can't ever happen */ + Error + ("Kiddie(): console socket state == %d -- THIS IS A BUG", + pCEServing->ioState); + /* no ConsoleError() for same reason as above */ + ConsDown(pCEServing, FLAGTRUE, FLAGTRUE); + break; } } - - /* anything from a connection? - */ - for (pCLServing = pGE->pCLall; (CONSCLIENT *) 0 != pCLServing; + /* anything on a client? */ + for (pCLServing = pGE->pCLall; (CONSCLIENT *)0 != pCLServing; pCLServing = pCLServing->pCLscan) { - if (!FD_ISSET(FileFDNum(pCLServing->fd), &rmask)) { - continue; - } - pCEServing = pCLServing->pCEto; - - /* read connection */ - if ((nr = FileRead(pCLServing->fd, acIn, sizeof(acIn))) == 0) { - /* reached EOF - close connection */ - drop: - /* re-entry point to drop a connection - * (for any other reason) - */ - DisconnectClient(pGE, pCLServing, (char *)0); -#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - Debug(1, "Kiddie(): dmalloc / MarkClientConnection"); - dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); -#endif - continue; - } - - /* update last keystroke time - */ - pCLServing->typetym = tyme = time((time_t *) 0); - - for (i = 0; i < nr; ++i) { - acInOrig[i] = acIn[i]; - if (fStrip) { - acIn[i] &= 127; - } - } - - for (i = 0; i < nr; ++i) - switch (pCLServing->iState) { - case S_BCAST: - /* gather message */ - if ('\r' != acIn[i]) { - if (acIn[i] == '\a' || - (acIn[i] >= ' ' && acIn[i] <= '~')) { - BuildStringChar(acIn[i], &pCLServing->msg); - if (pGE->pCEctl != pCEServing) - FileWrite(pCLServing->fd, - (char *)&acIn[i], 1); - } else if ((acIn[i] == '\b' || acIn[i] == 0x7f) - && pCLServing->msg.used > 1) { - if (pCLServing->msg. - string[pCLServing->msg.used - 2] != - '\a' && pGE->pCEctl != pCEServing) { - FileWrite(pCLServing->fd, "\b \b", 3); - } - pCLServing->msg.string[pCLServing->msg. - used - 2] = '\000'; - pCLServing->msg.used--; - } - continue; - } - FileWrite(pCLServing->fd, "]\r\n", 3); - BuildString((char *)0, bcast); - BuildString("[", bcast); - if (pGE->pCEctl != pCEServing) { - BuildString(pCLServing->acid.string, bcast); - BuildString(": ", bcast); - BuildString(pCLServing->msg.string, bcast); - } else { - char *msg; - if ((msg = - strchr(pCLServing->msg.string, - ':')) == (char *)0) { - BuildString(pCLServing->acid.string, - bcast); - msg = pCLServing->msg.string; - } else { - *msg++ = '\000'; - BuildString(pCLServing->msg.string, bcast); - BuildStringChar('@', bcast); - BuildString(pCLServing->peername.string, - bcast); - } - BuildString("?: ", bcast); - BuildString(msg, bcast); - } - BuildString("]\r\n", bcast); - if (pGE->pCEctl != pCEServing) - SendClientsMsg(pCEServing, bcast->string); - else - SendAllClientsMsg(pGE, bcast->string); - - BuildString((char *)0, &pCLServing->msg); - pCLServing->iState = S_NORMAL; - continue; - - case S_IDENT: - /* append chars to acid until [\r]\n - */ - if ('\n' != acIn[i]) { - BuildStringChar(acIn[i], &pCLServing->acid); - continue; - } - if ((pCLServing->acid.used > 1) && - ('\r' == - pCLServing->acid.string[pCLServing->acid. - used - 2])) { - pCLServing->acid.string[pCLServing->acid.used - - 2] = '\000'; - pCLServing->acid.used--; - } - BuildStringChar('@', &pCLServing->acid); - BuildString(pCLServing->peername.string, - &pCLServing->acid); - Debug(1, - "Kiddie(): client acid reinitialized to `%s'", - pCLServing->acid.string); - BuildString((char *)0, &pCLServing->accmd); - FileWrite(pCLServing->fd, "host:\r\n", -1); - pCLServing->iState = S_HOST; - continue; - - case S_HOST: - /* append char to buffer, check for \n - * continue if incomplete - * else switch to new host - */ - if ('\n' != acIn[i]) { - BuildStringChar(acIn[i], &pCLServing->accmd); - continue; - } - if ((pCLServing->accmd.used > 1) && - ('\r' == - pCLServing->accmd.string[pCLServing->accmd. - used - 2])) { - pCLServing->accmd.string[pCLServing->accmd. - used - 2] = '\000'; - pCLServing->accmd.used--; - } - - /* try to move to the given console - */ - pCLServing->pCEwant = (CONSENT *) 0; - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - if (0 == - strcasecmp(pCLServing->accmd.string, - pCE->server.string)) { - pCLServing->pCEwant = pCE; - BuildString((char *)0, &pCLServing->accmd); - break; - } - } - if ((CONSENT *) 0 == pCLServing->pCEwant) { - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - if (0 == - strncasecmp(pCLServing->accmd.string, - pCE->server.string, - pCLServing->accmd.used - - 1)) { - pCLServing->pCEwant = pCE; - BuildString((char *)0, - &pCLServing->accmd); - break; - } - } - } - if ((CONSENT *) 0 == pCLServing->pCEwant) { - FilePrint(pCLServing->fd, - "%s: no such console\r\n", - pCLServing->accmd.string); - BuildString((char *)0, &pCLServing->accmd); - goto drop; - } - BuildString((char *)0, &pCLServing->accmd); - - if (('t' == pCLServing->caccess) || - (CheckPasswd(pCLServing, "") == - AUTH_SUCCESS)) { - goto shift_console; - } - FileWrite(pCLServing->fd, "passwd:\r\n", -1); - pCLServing->iState = S_PASSWD; - continue; - - case S_PASSWD: - /* gather passwd, check and drop or - * set new state - */ - if ('\n' != acIn[i]) { - BuildStringChar(acIn[i], &pCLServing->accmd); - continue; - } - if ((pCLServing->accmd.used > 1) && - ('\r' == - pCLServing->accmd.string[pCLServing->accmd. - used - 2])) { - pCLServing->accmd.string[pCLServing->accmd. - used - 2] = '\000'; - pCLServing->accmd.used--; - } - - if (CheckPasswd - (pCLServing, - pCLServing->accmd.string) != AUTH_SUCCESS) { - FileWrite(pCLServing->fd, "Sorry.\r\n", -1); - Msg("[%s] user %s bad passwd", - pCLServing->pCEwant->server.string, - pCLServing->acid.string); - BuildString((char *)0, &pCLServing->accmd); - goto drop; - } -#if HAVE_MEMSET - memset((void *)pCLServing->accmd.string, 0, - pCLServing->accmd.used); -#else - bzero((char *)pCLServing->accmd.string, - pCLServing->accmd.used); -#endif - BuildString((char *)0, &pCLServing->accmd); - shift_console: - /* remove from current host - */ - if ((CONSCLIENT *) 0 != pCLServing->pCLnext) { - pCLServing->pCLnext->ppCLbnext = - pCLServing->ppCLbnext; - } - *(pCLServing->ppCLbnext) = pCLServing->pCLnext; - if (pCLServing->fwr) { - pCLServing->fwr = 0; - pCLServing->fwantwr = 0; - TagLogfileAct(pCEServing, "%s detached", - pCLServing->acid.string); - pCEServing->pCLwr = - FindWrite(pCEServing->pCLon); - } - - /* inform operators of the change - */ - if (pGE->pCEctl == pCEServing) { - Msg("[%s] login %s", - pCLServing->pCEwant->server.string, - pCLServing->acid.string); - } else { - Msg("[%s] %s moves to %s", - pCEServing->server.string, - pCLServing->acid.string, - pCLServing->pCEwant->server.string); - } - - /* set new host and link into new host list - */ - pCEServing = pCLServing->pCEwant; - pCLServing->pCEto = pCEServing; - pCLServing->pCLnext = pCEServing->pCLon; - pCLServing->ppCLbnext = &pCEServing->pCLon; - if ((CONSCLIENT *) 0 != pCLServing->pCLnext) { - pCLServing->pCLnext->ppCLbnext = - &pCLServing->pCLnext; - } - pCEServing->pCLon = pCLServing; - - /* try to reopen line if specified at server startup - */ - if ((fNoinit || fReopen) && !pCEServing->fup) - ConsInit(pCEServing, &pGE->rinit, 0); - - /* try for attach on new console - */ - if (!pCEServing->fup) { - FileWrite(pCLServing->fd, - "line to host is down]\r\n", -1); - } else if (pCEServing->fronly) { - FileWrite(pCLServing->fd, - "host is read-only]\r\n", -1); - } else if ((CONSCLIENT *) 0 == pCEServing->pCLwr) { - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - FileWrite(pCLServing->fd, "attached]\r\n", -1); - /* this keeps the ops console neat */ - pCEServing->iend = 0; - TagLogfileAct(pCEServing, "%s attached", - pCLServing->acid.string); - } else { - FileWrite(pCLServing->fd, "spy]\r\n", -1); - } - pCLServing->fcon = 1; - pCLServing->iState = S_NORMAL; - continue; - - case S_QUOTE: /* send octal code */ - /* must type in 3 octal digits */ - if (acIn[i] >= '0' && acIn[i] <= '7') { - BuildStringChar(acIn[i], &pCLServing->accmd); - if (pCLServing->accmd.used < 4) { - FileWrite(pCLServing->fd, (char *)&acIn[i], - 1); - continue; - } - FileWrite(pCLServing->fd, (char *)&acIn[i], 1); - FileWrite(pCLServing->fd, "]", 1); - - pCLServing->accmd.string[0] = - (((pCLServing->accmd.string[0] - '0') * 8 + - (pCLServing->accmd.string[1] - - '0')) * 8) + - (pCLServing->accmd.string[2] - '0'); - PutConsole(pCEServing, - pCLServing->accmd.string[0]); - BuildString((char *)0, &pCLServing->accmd); - } else { - FileWrite(pCLServing->fd, " aborted]\r\n", -1); - } - pCLServing->iState = S_NORMAL; - continue; - - case S_SUSP: - if (!pCEServing->fup) { - FileWrite(pCLServing->fd, " -- line down]\r\n", - -1); - } else if (pCEServing->fronly) { - FileWrite(pCLServing->fd, " -- read-only]\r\n", - -1); - } else if ((CONSCLIENT *) 0 == pCEServing->pCLwr) { - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, - " -- attached (nologging)]\r\n", - -1); - } else { - FileWrite(pCLServing->fd, - " -- attached]\r\n", -1); - } - TagLogfileAct(pCEServing, "%s attached", - pCLServing->acid.string); - } else { - FileWrite(pCLServing->fd, " -- spy mode]\r\n", - -1); - } - pCLServing->fcon = 1; - pCLServing->iState = S_NORMAL; - continue; - - case S_NORMAL: - /* if it is an escape sequence shift states - */ - if (acInOrig[i] == pCLServing->ic[0]) { - pCLServing->iState = S_ESC1; - continue; - } - /* if we can write, write to slave tty - */ - if (pCLServing->fwr) { - PutConsole(pCEServing, acIn[i]); - continue; - } - /* if the client is stuck in spy mode - * give them a clue as to how to get out - * (LLL nice to put chars out as ^Ec, rather - * than octal escapes, but....) - */ - if ('\r' == acIn[i] || '\n' == acIn[i]) { - FilePrint(pCLServing->fd, - "[read-only -- use %s %s ? for help]\r\n", - FmtCtl(pCLServing->ic[0], acA1), - FmtCtl(pCLServing->ic[1], acA2)); - } - continue; - - case S_HALT1: /* halt sequence? */ - pCLServing->iState = S_NORMAL; - if (acIn[i] != '?' && - (acIn[i] < '0' || acIn[i] > '9')) { - FileWrite(pCLServing->fd, "aborted]\r\n", -1); - continue; - } - - if (acIn[i] == '?') { - int i; - FileWrite(pCLServing->fd, "list]\r\n", -1); - i = pCEServing->breakType; - if (i == 0 || breakList[i - 1].used <= 1) - FileWrite(pCLServing->fd, - " 0 \r\n", -1); - else { - FilePrint(pCLServing->fd, " 0 `%s'\r\n", - breakList[i - 1].string); - } - for (i = 0; i < 9; i++) { - if (breakList[i].used > 1) { - FilePrint(pCLServing->fd, - " %d `%s'\r\n", i + 1, - breakList[i].string); - } - } - } else { - int bt = acIn[i] - '0'; - SendBreak(pCLServing, pCEServing, bt); - } - continue; - - case S_CATTN: /* redef escape sequence? */ - pCLServing->ic[0] = acInOrig[i]; - FmtCtl(acInOrig[i], acA1); - FilePrint(pCLServing->fd, "%s ", acA1->string); - pCLServing->iState = S_CESC; - continue; - - case S_CESC: /* escape sequent 2 */ - pCLServing->ic[1] = acInOrig[i]; - pCLServing->iState = S_NORMAL; - FmtCtl(acInOrig[i], acA1); - FilePrint(pCLServing->fd, "%s ok]\r\n", - acA1->string); - continue; - - case S_ESC1: /* first char in escape sequence */ - if (acInOrig[i] == pCLServing->ic[1]) { - if (pCLServing->fecho) - FileWrite(pCLServing->fd, "\r\n[", -1); - else - FileWrite(pCLServing->fd, "[", -1); - pCLServing->iState = S_CMD; - continue; - } - /* ^E^Ec or ^_^_^[ - * pass (possibly stripped) first ^E (^_) and - * stay in same state - */ - if (acInOrig[i] == pCLServing->ic[0]) { - if (pCLServing->fwr) { - PutConsole(pCEServing, acIn[i]); - } - continue; - } - /* ^Ex or ^_x - * pass both characters to slave tty (possibly stripped) - */ - pCLServing->iState = S_NORMAL; - if (pCLServing->fwr) { - char c = pCLServing->ic[0]; - if (fStrip) - c = c & 127; - PutConsole(pCEServing, c); - PutConsole(pCEServing, acIn[i]); - } - continue; - - case S_CMD: /* have 1/2 of the escape sequence */ - pCLServing->iState = S_NORMAL; - switch (acIn[i]) { - case '+': - case '-': - if (0 != - (pCLServing->fecho = '+' == acIn[i])) - FileWrite(pCLServing->fd, - "drop line]\r\n", -1); - else - FileWrite(pCLServing->fd, - "no drop line]\r\n", -1); - break; - + switch (pCLServing->ioState) { #if HAVE_OPENSSL - case '*': /* SSL encryption */ - if (pGE->pCEctl != pCLServing->pCEto) { - goto unknown; - } - FileWrite(pCLServing->fd, "ssl:\r\n", -1); - if (!AttemptSSL(pCLServing)) - goto drop; - Debug(1, - "Kiddie(): SSL connection a success for client `%s'", - pCLServing->peername.string); - break; + case INSSLACCEPT: + if (FileCanSSLAccept(pCLServing->fd, &rmask, &wmask)) { + int r; + if ((r = FileSSLAccept(pCLServing->fd)) < 0) + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + else if (r == 1) + pCLServing->ioState = ISNORMAL; + } + break; #endif - - case ';': /* ;login: */ - if (pGE->pCEctl != pCLServing->pCEto) { - goto unknown; - } -#if HAVE_OPENSSL - if (fReqEncryption && - FileGetType(pCLServing->fd) != - SSLSocket) { - FileWrite(pCLServing->fd, - "Encryption required\r\n", - -1); - goto drop; - } -#endif - FileWrite(pCLServing->fd, "login:\r\n", - -1); - BuildString((char *)0, &pCLServing->acid); - pCLServing->iState = S_IDENT; - break; - - case 'b': /* broadcast message */ - case 'B': - FileWrite(pCLServing->fd, - "Enter message: ", -1); - pCLServing->iState = S_BCAST; - break; - - case 'a': /* attach */ - case 'A': - if (pGE->pCEctl == pCEServing) { - FileWrite(pCLServing->fd, - "no -- on ctl]\r\n", -1); - } else if (!pCEServing->fup) { - FileWrite(pCLServing->fd, - "line to host is down]\r\n", - -1); - } else if (pCEServing->fronly) { - FileWrite(pCLServing->fd, - "host is read-only]\r\n", - -1); - } else if ((CONSCLIENT *) 0 == - (pCL = pCEServing->pCLwr)) { - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, - "attached (nologging)]\r\n", - -1); - } else { - FileWrite(pCLServing->fd, - "attached]\r\n", -1); - } - TagLogfileAct(pCEServing, - "%s attached", - pCLServing->acid.string); - } else if (pCL == pCLServing) { - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, - "ok (nologging)]\r\n", - -1); - } else { - FileWrite(pCLServing->fd, - "ok]\r\n", -1); - } - } else { - pCLServing->fwantwr = 1; - FilePrint(pCLServing->fd, - "no, %s is attached]\r\n", - pCL->acid.string); - } - break; - - case 'c': - case 'C': - if (pCEServing->isNetworkConsole) { - continue; - } - if (pCEServing->fvirtual) { - continue; - } -#if HAVE_TERMIOS_H - if (-1 == - tcgetattr(pCEServing->fdtty, &sbuf)) { - FileWrite(pCLServing->fd, - "failed]\r\n", -1); - continue; - } - if (0 != (sbuf.c_iflag & IXOFF)) { - sbuf.c_iflag &= ~(IXOFF | IXON); - FileWrite(pCLServing->fd, - "flow OFF]\r\n", -1); - } else { - sbuf.c_iflag |= IXOFF | IXON; - FileWrite(pCLServing->fd, - "flow ON]\r\n", -1); - } - if (-1 == - tcsetattr(pCEServing->fdtty, TCSANOW, - &sbuf)) { - FileWrite(pCLServing->fd, - "failed]\r\n", -1); - continue; - } -#else - if (-1 == - ioctl(pCEServing->fdtty, TIOCGETP, - (char *)&sty)) { - FileWrite(pCLServing->fd, - "failed]\r\n", -1); - break; - } - if (0 != (sty.sg_flags & TANDEM)) { - sty.sg_flags &= ~TANDEM; - FileWrite(pCLServing->fd, - "flow OFF]\r\n", -1); - } else { - sty.sg_flags |= TANDEM; - FileWrite(pCLServing->fd, - "flow ON]\r\n", -1); - } - ioctl(pCEServing->fdtty, TIOCSETP, - (char *)&sty); -#endif - break; - - case 'd': /* down a console */ - case 'D': - if (pGE->pCEctl == pCEServing) { - FileWrite(pCLServing->fd, - "no -- on ctl]\r\n", -1); - continue; - } - if (!pCLServing->fwr && - !pCEServing->fronly) { - FileWrite(pCLServing->fd, - "attach to down line]\r\n", - -1); - break; - } - if (!pCEServing->fup) { - FileWrite(pCLServing->fd, "ok]\r\n", - -1); - break; - } - - pCLServing->fwr = 0; - pCEServing->pCLwr = (CONSCLIENT *) 0; - TagLogfileAct(pCEServing, "%s detached", - pCLServing->acid.string); - ConsDown(pCEServing, &pGE->rinit, 0); - FileWrite(pCLServing->fd, "line down]\r\n", - -1); - - /* tell all who closed it */ - for (pCL = pCEServing->pCLon; - (CONSCLIENT *) 0 != pCL; - pCL = pCL->pCLnext) { - if (pCL == pCLServing) - continue; - if (pCL->fcon) { - FilePrint(pCL->fd, - "[line down by %s]\r\n", - pCLServing->acid.string); - } - } - break; - - case 'e': /* redefine escape keys */ - case 'E': - pCLServing->iState = S_CATTN; - FileWrite(pCLServing->fd, "redef: ", -1); - break; - - case 'f': /* force attach */ - case 'F': - if (pGE->pCEctl == pCEServing) { - FileWrite(pCLServing->fd, - "no -- on ctl]\r\n", -1); - continue; - } else if (pCEServing->fronly) { - FileWrite(pCLServing->fd, - "host is read-only]\r\n", - -1); - continue; - } else if (!pCEServing->fup) { - FileWrite(pCLServing->fd, - "line to host is down]\r\n", - -1); - continue; - } - if ((CONSCLIENT *) 0 != - (pCL = pCEServing->pCLwr)) { - if (pCL == pCLServing) { - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, - "ok (nologging)]\r\n", - -1); - } else { - FileWrite(pCLServing->fd, - "ok]\r\n", -1); - } - break; - } - pCL->fwr = 0; - pCL->fwantwr = 1; - if (pCEServing->nolog) { - FilePrint(pCLServing->fd, - "bumped %s (nologging)]\r\n", - pCL->acid.string); - } else { - FilePrint(pCLServing->fd, - "bumped %s]\r\n", - pCL->acid.string); - } - FileWrite(pCL->fd, - "\r\n[forced to `spy' mode by ", - -1); - FileWrite(pCL->fd, - pCLServing->acid.string, -1); - FileWrite(pCL->fd, "]\r\n", -1); - TagLogfileAct(pCEServing, - "%s bumped %s", - pCLServing->acid.string, - pCL->acid.string); - } else { - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, - "attached (nologging)]\r\n", - -1); - } else { - FileWrite(pCLServing->fd, - "attached]\r\n", -1); - } - TagLogfileAct(pCEServing, - "%s attached", - pCLServing->acid.string); - } - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - break; - - case 'g': /* group info */ - case 'G': - /* we do not show the ctl console - * else we'd get the client always - */ - FilePrint(pCLServing->fd, "group %s]\r\n", - pGE->pCEctl->server.string); - for (pCL = pGE->pCLall; - (CONSCLIENT *) 0 != pCL; - pCL = pCL->pCLscan) { - if (pGE->pCEctl == pCL->pCEto) - continue; - sprintf((char *)acOut, - " %-32.32s %c %-7.7s %6s ", - pCL->acid.string, - pCL == pCLServing ? '*' : ' ', - pCL->fcon ? (pCL-> - fwr ? "attach" : - "spy") : - "stopped", - IdleTyme(tyme - pCL->typetym)); - FileWrite(pCLServing->fd, - (char *)acOut, -1); - FilePrint(pCLServing->fd, "%s\r\n", - pCL->pCEto->server.string); - } - break; - - case 'P': /* DEC vt100 pf1 */ - case 'h': /* help */ - case 'H': - case '?': - HelpUser(pCLServing); - break; - - case 'i': - case 'I': - FileWrite(pCLServing->fd, "info]\r\n", -1); - for (pCE = pGE->pCElist; - pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - int comma = 0; - FilePrint(pCLServing->fd, - "%s:%s,%lu,%hu:", - pCE->server.string, acMyHost, - (unsigned long)thepid, - pGE->port); - if (pCE->fvirtual) { - FilePrint(pCLServing->fd, - "|:%s,%lu,%s", - (pCE->pccmd.used > - 1 ? pCE->pccmd. - string : defaultShell-> - string), - (unsigned long)pCE->ipid, - pCE->acslave.string); - } else if (pCE->isNetworkConsole) { - FilePrint(pCLServing->fd, - "!:%s,%hu", - pCE->networkConsoleHost. - string, - pCE->networkConsolePort); - } else { - FilePrint(pCLServing->fd, - "/:%s,%s%c", - pCE->dfile.string, - (pCE->pbaud ? pCE-> - pbaud->acrate : ""), - (pCE->pparity ? pCE-> - pparity->ckey : ' ')); - } - FilePrint(pCLServing->fd, ",%d:", - pCE->fdtty); - if (pCE->pCLwr) { - FilePrint(pCLServing->fd, - "w@%s@%ld", - pCE->pCLwr->acid.string, - tyme - - pCE->pCLwr->typetym); - comma = 1; - } - - for (pCL = pCE->pCLon; - (CONSCLIENT *) 0 != pCL; - pCL = pCL->pCLnext) { - if (pCL == pCE->pCLwr) - continue; - if (comma) - FilePrint(pCLServing->fd, ","); - if (pCL->fcon) - FilePrint(pCLServing->fd, - "r@%s@%ld@%s", - pCL->acid.string, - tyme - pCL->typetym, - pCL-> - fwantwr ? "rw" : - "ro"); - else - FilePrint(pCLServing->fd, - "s@%s@%ld@%s", - pCL->acid.string, - tyme - pCL->typetym, - pCL-> - fwantwr ? "rw" : - "ro"); - comma = 1; - } - - FilePrint(pCLServing->fd, - ":%s:%s:%s,%s,%s,%s,%d,%d:%d:%s\r\n", - (pCE->fup ? "up" : "down"), - (pCE->fronly ? "ro" : "rw"), - pCE->lfile.string, - (pCE-> - nolog ? "nolog" : "log"), - (pCE-> - activitylog ? "act" : - "noact"), - (pCE-> - breaklog ? "brk" : "nobrk"), - pCE->mark, - (pCE->fdlog ? pCE->fdlog-> - fd : -1), pCE->breakType, - (pCE-> - autoReUp ? "autoup" : - "noautoup")); - } - break; - case 'L': - if (pCLServing->fwr) { - pCEServing->nolog = !pCEServing->nolog; - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, - "logging off]\r\n", -1); - TagLogfile(pCEServing, - "Console logging disabled by %s", - pCLServing->acid. - string); - } else { - FileWrite(pCLServing->fd, - "logging on]\r\n", -1); - TagLogfile(pCEServing, - "Console logging restored by %s", - pCLServing->acid. - string); - } - } else { - FilePrint(pCLServing->fd, - "read-only -- use %s %s ? for help]\r\n", - FmtCtl(pCLServing->ic[0], - acA1), - FmtCtl(pCLServing->ic[1], - acA2)); - } - break; - - case 'l': /* halt character 1 */ - if (pCEServing->fronly) { - FileWrite(pCLServing->fd, - "can't halt read-only host]\r\n", - -1); - continue; - } - if (!pCLServing->fwr) { - FileWrite(pCLServing->fd, - "attach to halt]\r\n", -1); - continue; - } - pCLServing->iState = S_HALT1; - FileWrite(pCLServing->fd, "halt ", -1); - break; - - case 'o': /* close and re-open line */ - case 'O': - if (pGE->pCEctl == pCEServing) { - FileWrite(pCLServing->fd, - "no -- on ctl]\r\n", -1); - continue; - } - /* with a close/re-open we might - * change fd's - */ - ConsInit(pCEServing, &pGE->rinit, 0); - if (!pCEServing->fup) { - FileWrite(pCLServing->fd, - "line to host is down]\r\n", - -1); - } else if (pCEServing->fronly) { - FileWrite(pCLServing->fd, - "up read-only]\r\n", -1); - } else if ((CONSCLIENT *) 0 == - (pCL = pCEServing->pCLwr)) { - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - FileWrite(pCLServing->fd, - "up -- attached]\r\n", -1); - TagLogfileAct(pCEServing, - "%s attached", - pCLServing->acid.string); - } else if (pCL == pCLServing) { - FileWrite(pCLServing->fd, "up]\r\n", - -1); - TagLogfileAct(pCEServing, - "%s attached", - pCLServing->acid.string); - } else { - FilePrint(pCLServing->fd, - "up, %s is attached]\r\n", - pCL->acid.string); - } - break; - - case '\022': /* ^R */ - FileWrite(pCLServing->fd, "^R]\r\n", -1); - Replay(pCEServing->fdlog, pCLServing->fd, - 1); - break; - - case 'R': /* DEC vt100 pf3 */ - case 'r': /* replay 20 lines */ - FileWrite(pCLServing->fd, "replay]\r\n", - -1); - Replay(pCEServing->fdlog, pCLServing->fd, - 20); - break; - - case 'p': /* replay 60 lines */ - FileWrite(pCLServing->fd, - "long replay]\r\n", -1); - Replay(pCEServing->fdlog, pCLServing->fd, - 60); - break; - - case 'S': /* DEC vt100 pf4 */ - case 's': /* spy mode */ - pCLServing->fwantwr = 0; - if (!pCLServing->fwr) { - FileWrite(pCLServing->fd, "ok]\r\n", - -1); - break; - } - pCLServing->fwr = 0; - TagLogfileAct(pCEServing, "%s detached", - pCLServing->acid.string); - pCEServing->pCLwr = - FindWrite(pCEServing->pCLon); - FileWrite(pCLServing->fd, "spying]\r\n", - -1); - break; - - case 'u': /* hosts on server this */ - case 'U': - FileWrite(pCLServing->fd, "hosts]\r\n", - -1); - for (pCE = pGE->pCElist; - pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - sprintf((char *)acOut, - " %-24.24s %c %-4.4s %-.40s\r\n", - pCE->server.string, - pCE == pCEServing ? '*' : ' ', - pCE->fup ? "up" : "down", - pCE->pCLwr ? pCE->pCLwr->acid. - string : pCE-> - pCLon ? "" : ""); - FileWrite(pCLServing->fd, - (char *)acOut, -1); - } - break; - - case 'v': /* version */ - case 'V': - FilePrint(pCLServing->fd, - "version `%s']\r\n", - THIS_VERSION); - break; - - case 'w': /* who */ - case 'W': - FilePrint(pCLServing->fd, "who %s]\r\n", - pCEServing->server.string); - for (pCL = pCEServing->pCLon; - (CONSCLIENT *) 0 != pCL; - pCL = pCL->pCLnext) { - sprintf((char *)acOut, - " %-32.32s %c %-7.7s %6s %s\r\n", - pCL->acid.string, - pCL == pCLServing ? '*' : ' ', - pCL->fcon ? (pCL-> - fwr ? "attach" : - "spy") : - "stopped", - IdleTyme(tyme - pCL->typetym), - pCL->actym); - FileWrite(pCLServing->fd, - (char *)acOut, -1); - } - break; - - case 'x': - case 'X': - FileWrite(pCLServing->fd, "examine]\r\n", - -1); - for (pCE = pGE->pCElist; - pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - sprintf((char *)acOut, - " %-24.24s on %-32.32s at %5.5s%c\r\n", - pCE->server.string, - pCE->fvirtual ? pCE->acslave. - string : pCE->dfile.string, - pCE->pbaud->acrate, - pCE->pparity->ckey); - FileWrite(pCLServing->fd, - (char *)acOut, -1); - } - break; - - case 'z': /* suspend the client */ - case 'Z': - case '\032': - if (1 != - FileSend(pCLServing->fd, acStop, 1, - MSG_OOB)) { - break; - } - pCLServing->fcon = 0; - pCLServing->iState = S_SUSP; - if (pCEServing->pCLwr == pCLServing) { - pCLServing->fwr = 0; - pCLServing->fwantwr = 0; - pCEServing->pCLwr = (CONSCLIENT *) 0; - TagLogfileAct(pCEServing, - "%s detached", - pCLServing->acid.string); - } - break; - - case '\t': /* toggle tab expand */ - FileWrite(pCLServing->fd, "tabs]\r\n", -1); -#if HAVE_TERMIO_H - /* ZZZ */ -#else -# if HAVE_TERMIOS_H - if (-1 == - tcgetattr(pCEServing->fdtty, &sbuf)) { - FileWrite(pCLServing->fd, - "failed]\r\n", -1); - continue; - } -# if !defined(XTABS) /* XXX hack */ -# define XTABS TAB3 -# endif - if (XTABS == (TABDLY & sbuf.c_oflag)) { - sbuf.c_oflag &= ~TABDLY; - sbuf.c_oflag |= TAB0; - } else { - sbuf.c_oflag &= ~TABDLY; - sbuf.c_oflag |= XTABS; - } - if (-1 == - tcsetattr(pCEServing->fdtty, TCSANOW, - &sbuf)) { - FileWrite(pCLServing->fd, - "failed]\r\n", -1); - continue; - } -# else - /* ZZZ */ -# endif -#endif - break; - - case 'Q': /* DEC vt100 PF2 */ - case '.': /* disconnect */ - case '\004': - case '\003': - FileWrite(pCLServing->fd, - "disconnect]\r\n", -1); - nr = 0; - if (!pCEServing->fup) { - goto drop; - } - if (pCEServing->isNetworkConsole) { - goto drop; - } - if (pCEServing->fvirtual) { - goto drop; - } -#if HAVE_TERMIOS_H - if (-1 == - tcgetattr(pCEServing->fdtty, &sbuf)) { - FileWrite(pCLServing->fd, - "[failed]\r\n", -1); - continue; - } - if (0 == (sbuf.c_iflag & IXOFF)) { - sbuf.c_iflag |= IXOFF | IXON; - tcsetattr(pCEServing->fdtty, TCSANOW, - &sbuf); - } -#else - if (-1 != - ioctl(pCEServing->fdtty, TIOCGETP, - (char *)&sty) && - 0 == (sty.sg_flags & TANDEM)) { - sty.sg_flags |= TANDEM; - ioctl(pCEServing->fdtty, TIOCSETP, - (char *)&sty); - } -#endif - goto drop; - - case ' ': /* abort escape sequence */ - case '\n': - case '\r': - FileWrite(pCLServing->fd, "ignored]\r\n", - -1); - break; - - case '\\': /* quote mode (send ^Q,^S) */ - if (pCEServing->fronly) { - FileWrite(pCLServing->fd, - "can't write to read-only host]\r\n", - -1); - continue; - } - if (!pCLServing->fwr) { - FileWrite(pCLServing->fd, - "attach to send character]\r\n", - -1); - continue; - } - BuildString((char *)0, &pCLServing->accmd); - pCLServing->iState = S_QUOTE; - FileWrite(pCLServing->fd, "quote \\", -1); - break; - - default: /* unknown sequence */ - unknown: - FileWrite(pCLServing->fd, - "unknown -- use `?']\r\n", -1); - break; + case ISNORMAL: + if (FileCanRead(pCLServing->fd, &rmask, &wmask)) + DoClientRead(pGE, pCLServing); + /* fall through to ISFLUSHING for buffered data */ + case ISFLUSHING: + if (!FileBufEmpty(pCLServing->fd) && + FileCanWrite(pCLServing->fd, &rmask, &wmask)) { + CONDDEBUG((1, "Kiddie(): flushing fd %d", + FileFDNum(pCLServing->fd))); + if (FileWrite(pCLServing->fd, (char *)0, 0) < 0) { + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGTRUE); + break; } - continue; - } + } + if ((pCLServing->ioState == ISFLUSHING) && + FileBufEmpty(pCLServing->fd)) + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + break; + default: + /* this really can't ever happen */ + Error + ("Kiddie(): client socket state == %d -- THIS IS A BUG", + pCLServing->ioState); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + break; + } } + /* we buffered console data in PutConsole() so that we can + * send more than 1-byte payloads, if we get more than 1-byte + * of data from a client connection. here we flush that buffer, + * possibly putting it into the write buffer (but we don't really + * need to worry about that here. + */ + for (pCEServing = pGE->pCElist; pCEServing != (CONSENT *)0; + pCEServing = pCEServing->pCEnext) { + int justHadDelay = 0; + if (pCEServing->wbuf->used <= 1) + continue; + if (!pCEServing->fup) { + /* if we have data but aren't up, drop it */ + BuildString((char *)0, pCEServing->wbuf); + pCEServing->wbufIAC = 0; + continue; + } + while (!justHadDelay && pCEServing->wbuf->used > 1) { + if (pCEServing->wbufIAC == 0) { + CONDDEBUG((1, + "Kiddie(): flushing %d non-IAC bytes to fd %d", + pCEServing->wbuf->used - 1, + FileFDNum(pCEServing->cofile))); + if (FileWrite + (pCEServing->cofile, pCEServing->wbuf->string, + pCEServing->wbuf->used - 1) < 0) { + ConsoleError(pCEServing); + break; + } + BuildString((char *)0, pCEServing->wbuf); + } else { + unsigned char next; + + /* this should never really happen...but in case it + * does, just reset wbufIAC and try again. + */ + if (pCEServing->wbuf->used < pCEServing->wbufIAC) { + CONDDEBUG((1, + "Kiddie(): invalid wbufIAC setting for fd %d", + FileFDNum(pCEServing->cofile))); + } else { + if ((((next = + (unsigned char)pCEServing->wbuf-> + string[pCEServing->wbufIAC - 1]) >= '1' && + next <= '9') || (next == BREAK && + pCEServing->type != + HOST))) { + CONDDEBUG((1, "Kiddie(): heavy IAC for fd %d", + FileFDNum(pCEServing->cofile))); + /* if we have data before the IAC, send it */ + if (pCEServing->wbufIAC > 2) { + CONDDEBUG((1, + "Kiddie(): heavy IAC flushing %d leading bytes for fd %d", + pCEServing->wbufIAC - 2, + FileFDNum(pCEServing->cofile))); + if (FileWrite + (pCEServing->cofile, + pCEServing->wbuf->string, + pCEServing->wbufIAC - 2) < 0) { + ConsoleError(pCEServing); + break; + } + } + /* if we didn't flush everything, bail and get + * it the next time around (hopefully it'll have + * cleared...or will soon. + */ + if (!FileBufEmpty(pCEServing->cofile)) { + /* if we wrote something, shift it out */ + if (pCEServing->wbufIAC > 2) { + ShiftString(pCEServing->wbuf, + pCEServing->wbufIAC - 2); + pCEServing->wbufIAC = 2; + } + CONDDEBUG((1, + "Kiddie(): heavy IAC (wait for flush) for fd %d", + FileFDNum(pCEServing->cofile))); + break; + } + + /* Do the operation */ + if (next >= '1' && next <= '9') { + CONDDEBUG((1, + "Kiddie(): heavy IAC - doing usleep() for fd %d (break #%c - delay %dms)", + FileFDNum(pCEServing->cofile), + next, + breakList[next - '1'].delay)); + if (breakList[next - '1'].delay != 0) + usleep(breakList[next - '1'].delay * + 1000); + } else if (next == BREAK) { + CONDDEBUG((1, + "Kiddie(): heavy IAC - doing tcsendbreak() for fd %d", + FileFDNum(pCEServing->cofile))); + if (tcsendbreak + (FileFDNum(pCEServing->cofile), + 0) == -1) { + FileWrite(pCLServing->fd, + "[tcsendbreak() failed]\r\n", + -1); + return; + } + } + + /* shift things off and trigger completion */ + ShiftString(pCEServing->wbuf, + pCEServing->wbufIAC); + justHadDelay = 1; + /* we do this 'cause we just potentially paused for + * a half-second doing a break...or even the + * intentional usleep(). we could take out the + * justHadDelay bits and continue with the stream, + * but this allows us to process other consoles and + * then come around and do more on this one. you + * see, someone could have a '\d\z\d\z\d\z' sequence + * as a break string and we'd have about a 2 second + * delay added up if we process it all at once. + * we're just trying to be nice here. + */ + } else { + char *iac; + int offset = 0; + static STRING *buf = (STRING *)0; + + if (buf == (STRING *)0) + buf = AllocString(); + BuildString((char *)0, buf); + + do { + CONDDEBUG((1, + "Kiddie(): soft IAC for fd %d", + FileFDNum(pCEServing->cofile))); + if (pCEServing->wbufIAC == 0) { + /* if no more IAC chars, just throw the rest + * into the buffer, clear things, and stop + */ + CONDDEBUG((1, + "Kiddie(): soft IAC buffering to EOS for fd %d", + FileFDNum(pCEServing-> + cofile))); + BuildString(pCEServing->wbuf->string + + offset, buf); + offset = pCEServing->wbuf->used - 1; + break; + } + /* buffer everything up to the IAC */ + CONDDEBUG((1, + "Kiddie(): soft IAC buffering to IAC for fd %d", + FileFDNum(pCEServing->cofile))); + BuildStringN(pCEServing->wbuf->string + + offset, + pCEServing->wbufIAC - 2, buf); + /* process allowed sequences */ + if (next == IAC) { + CONDDEBUG((1, + "Kiddie(): soft IAC processing IAC for fd %d", + FileFDNum(pCEServing-> + cofile))); + BuildStringChar((char)IAC, buf); + } else if (next == BREAK && + pCEServing->type == HOST) { + CONDDEBUG((1, + "Kiddie(): soft IAC processing HOST BREAK for fd %d", + FileFDNum(pCEServing-> + cofile))); + BuildStringChar((char)IAC, buf); + BuildStringChar((char)BREAK, buf); + } else { + CONDDEBUG((1, + "Kiddie(): soft IAC unprocessable IAC for fd %d", + FileFDNum(pCEServing-> + cofile))); + /* move offset up to right before IAC */ + offset += pCEServing->wbufIAC - 2; + break; + } + /* bring offset past char after IAC */ + CONDDEBUG((1, + "Kiddie(): soft IAC looking for new IAC for fd %d", + FileFDNum(pCEServing->cofile))); + offset += pCEServing->wbufIAC; + iac = + strchr(pCEServing->wbuf->string + + offset, IAC); + if (iac == (char *)0) + pCEServing->wbufIAC = 0; + else + pCEServing->wbufIAC = + iac - (pCEServing->wbuf->string + + offset) + 2; + } while (offset < pCEServing->wbuf->used - 1); + + /* shift off the buffered data */ + CONDDEBUG((1, + "Kiddie(): soft IAC shifting off %d chars for fd %d", + offset, + FileFDNum(pCEServing->cofile))); + ShiftString(pCEServing->wbuf, offset); + + /* send the buffered data */ + CONDDEBUG((1, + "Kiddie(): soft IAC writing %d chars to fd %d", + buf->used - 1, + FileFDNum(pCEServing->cofile))); + if (FileWrite + (pCEServing->cofile, buf->string, + buf->used - 1) < 0) { + ConsoleError(pCEServing); + break; + } + BuildString((char *)0, buf); + } + } + CONDDEBUG((1, + "Kiddie(): hunting for new IAC for fd %d", + FileFDNum(pCEServing->cofile))); + /* hunt for a new IAC position */ + if (pCEServing->wbuf->used > 1) { + char *iac = strchr(pCEServing->wbuf->string, IAC); + if (iac == (char *)0) + pCEServing->wbufIAC = 0; + else + pCEServing->wbufIAC = + (iac - pCEServing->wbuf->string) + 2; + } else + pCEServing->wbufIAC = 0; + } + } + if (pCEServing->wbuf->used > 1) { + CONDDEBUG((1, + "Kiddie(): watching writability for fd %d 'cause we have buffered data", + FileFDNum(pCEServing->cofile))); + FD_SET(FileFDNum(pCEServing->cofile), &winit); + } else { + if (FileBufEmpty(pCEServing->cofile)) { + CONDDEBUG((1, + "Kiddie(): removing writability for fd %d 'cause we don't have buffered data", + FileFDNum(pCEServing->cofile))); + FD_CLR(FileFDNum(pCEServing->cofile), &winit); + } + } + } /* if nothing on control line, get more */ - if (!FD_ISSET(FileFDNum(sfd), &rmask)) { + if (!FD_ISSET(sfd, &rmask)) { continue; } @@ -3119,74 +3752,26 @@ Kiddie(pGE, sfd) dmallocMarkClientConnection = dmalloc_mark(); #endif so = sizeof(struct sockaddr_in); - fd = accept(FileFDNum(sfd), - (struct sockaddr *)&pGE->pCLfree->cnct_port, &so); + fd = accept(sfd, (struct sockaddr *)&pGE->pCLfree->cnct_port, &so); if (fd < 0) { Error("Kiddie(): accept(): %s", strerror(errno)); #if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - Debug(1, "Kiddie(): dmalloc / MarkClientConnection"); + CONDDEBUG((1, "Kiddie(): dmalloc / MarkClientConnection")); dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); #endif continue; } - pGE->pCLfree->fd = FileOpenFD(fd, simpleSocket); - if ((CONSFILE *) 0 == pGE->pCLfree->fd) { + if (SetFlags(sfd, O_NONBLOCK, 0)) + pGE->pCLfree->fd = FileOpenFD(fd, simpleSocket); + else + pGE->pCLfree->fd = (CONSFILE *)0; + + if ((CONSFILE *)0 == pGE->pCLfree->fd) { Error("Kiddie(): FileOpenFD(): %s", strerror(errno)); close(fd); #if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - Debug(1, "Kiddie(): dmalloc / MarkClientConnection"); - dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); -#endif - continue; - } -#if defined(USE_LIBWRAP) - { - struct request_info request; - request_init(&request, RQ_DAEMON, progname, RQ_FILE, fd, 0); - fromhost(&request); - if (!hosts_access(&request)) { - FileWrite(pGE->pCLfree->fd, - "access from your host refused\r\n", -1); - FileClose(&pGE->pCLfree->fd); - ResetMark(); -#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - Debug(1, "Kiddie(): dmalloc / MarkClientConnection"); - dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); -#endif - continue; - } - ResetMark(); - } -#endif - - /* We use this information to verify (ksb) - * the source machine as being local. - */ - so = sizeof(in_port); - if (-1 == getpeername(fd, (struct sockaddr *)&in_port, &so)) { - FileWrite(pGE->pCLfree->fd, "getpeername failed\r\n", -1); - FileClose(&pGE->pCLfree->fd); -#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - Debug(1, "Kiddie(): dmalloc / MarkClientConnection"); - dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); -#endif - continue; - } - so = sizeof(in_port.sin_addr); - if ((struct hostent *)0 == - (hpPeer = - gethostbyaddr((char *)&in_port.sin_addr, so, AF_INET))) { - cType = AccType(&in_port.sin_addr, NULL); - } else { - cType = AccType(&in_port.sin_addr, hpPeer->h_name); - } - if ('r' == cType) { - FileWrite(pGE->pCLfree->fd, - "access from your host refused\r\n", -1); - FileClose(&pGE->pCLfree->fd); -#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION - Debug(1, "Kiddie(): dmalloc / MarkClientConnection"); + CONDDEBUG((1, "Kiddie(): dmalloc / MarkClientConnection")); dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); #endif continue; @@ -3199,17 +3784,11 @@ Kiddie(pGE, sfd) /* init the identification stuff */ - BuildString((char *)0, &pCL->peername); - if (hpPeer == (struct hostent *)0) { - BuildString(inet_ntoa(in_port.sin_addr), &pCL->peername); - } else { - BuildString(hpPeer->h_name, &pCL->peername); - } - BuildString((char *)0, &pCL->acid); - BuildString("@", &pCL->acid); - BuildString(pCL->peername.string, &pCL->acid); - Debug(1, "Kiddie(): client acid initialized to `%s'", - pCL->acid.string); + BuildString((char *)0, pCL->peername); + BuildString((char *)0, pCL->acid); + BuildString("@", pCL->acid); + BuildString((char *)0, pCL->username); + BuildString("", pCL->username); strcpy(pCL->actym, StrTime(&(pCL->tym))); pCL->typetym = pCL->tym; @@ -3218,7 +3797,7 @@ Kiddie(pGE, sfd) pCL->pCEto = pGE->pCEctl; pCL->pCLnext = pGE->pCEctl->pCLon; pCL->ppCLbnext = &pGE->pCEctl->pCLon; - if ((CONSCLIENT *) 0 != pCL->pCLnext) { + if ((CONSCLIENT *)0 != pCL->pCLnext) { pCL->pCLnext->ppCLbnext = &pCL->pCLnext; } pGE->pCEctl->pCLon = pCL; @@ -3227,20 +3806,22 @@ Kiddie(pGE, sfd) */ pCL->pCLscan = pGE->pCLall; pCL->ppCLbscan = &pGE->pCLall; - if ((CONSCLIENT *) 0 != pCL->pCLscan) { + if ((CONSCLIENT *)0 != pCL->pCLscan) { pCL->pCLscan->ppCLbscan = &pCL->pCLscan; } pGE->pCLall = pCL; - FD_SET(FileFDNum(pCL->fd), &pGE->rinit); + FD_SET(FileFDNum(pCL->fd), &rinit); + if (maxfd < FileFDNum(pCL->fd) + 1) + maxfd = FileFDNum(pCL->fd) + 1; /* init the fsm */ pCL->fecho = 0; - pCL->iState = S_NORMAL; + pCL->iState = S_IDENT; pCL->ic[0] = DEFATTN; pCL->ic[1] = DEFESC; - pCL->caccess = cType; + BuildString((char *)0, pCL->accmd); /* mark as stopped (no output from console) * and spy only (on chars to console) @@ -3248,16 +3829,31 @@ Kiddie(pGE, sfd) pCL->fcon = 0; pCL->fwr = 0; pCL->fwantwr = 0; - FileWrite(pCL->fd, "ok\r\n", -1); /* remove from the free list * if we ran out of free slots, calloc one... */ - if ((CONSCLIENT *) 0 == pGE->pCLfree) { - pGE->pCLfree = (CONSCLIENT *) calloc(1, sizeof(CONSCLIENT)); - if ((CONSCLIENT *) 0 == pGE->pCLfree) + if ((CONSCLIENT *)0 == pGE->pCLfree) { + if ((pGE->pCLfree = + (CONSCLIENT *)calloc(1, sizeof(CONSCLIENT))) + == (CONSCLIENT *)0) OutOfMem(); + pGE->pCLfree->acid = AllocString(); + pGE->pCLfree->username = AllocString(); + pGE->pCLfree->peername = AllocString(); + pGE->pCLfree->accmd = AllocString(); + pGE->pCLfree->msg = AllocString(); } + + if (ClientAccessOk(pCL)) { + pCL->ioState = ISNORMAL; + /* say hi to start */ + FileWrite(pCL->fd, "ok\r\n", -1); + } else + DisconnectClient(pGE, pCLServing, (char *)0, FLAGFALSE); + BuildString(pCL->peername->string, pCL->acid); + CONDDEBUG((1, "Kiddie(): client acid initialized to `%s'", + pCL->acid->string)); } } @@ -3266,7 +3862,7 @@ Kiddie(pGE, sfd) */ void #if PROTOTYPES -Spawn(GRPENT * pGE) +Spawn(GRPENT *pGE) #else Spawn(pGE) GRPENT *pGE; @@ -3278,7 +3874,6 @@ Spawn(pGE) struct sockaddr_in lstn_port; int true = 1; unsigned short portInc = 0; - CONSFILE *ssocket; /* get a socket for listening */ @@ -3307,6 +3902,9 @@ Spawn(pGE) } #endif + if (!SetFlags(sfd, O_NONBLOCK, 0)) + Bye(EX_OSERR); + while (bind(sfd, (struct sockaddr *)&lstn_port, sizeof(lstn_port)) < 0) { if (bindBasePort && ( #if defined(EADDRINUSE) @@ -3315,7 +3913,8 @@ Spawn(pGE) (errno == EACCES)) && portInc++) { lstn_port.sin_port = htons(bindBasePort + portInc); } else { - Error("Spawn(): bind(%u): %s", sfd, strerror(errno)); + Error("Spawn(): bind(%hu): %s", ntohs(lstn_port.sin_port), + strerror(errno)); Bye(EX_OSERR); } } @@ -3325,7 +3924,7 @@ Spawn(pGE) Error("Spawn(): getsockname(%u): %s", sfd, strerror(errno)); Bye(EX_OSERR); } - pGE->port = lstn_port.sin_port; + pGE->port = ntohs(lstn_port.sin_port); fflush(stderr); fflush(stdout); @@ -3355,20 +3954,12 @@ Spawn(pGE) break; } if (listen(sfd, SOMAXCONN) < 0) { - Error("Spawn(): listen(%u): %s", sfd, strerror(errno)); + Error("Spawn(): listen(%hu): %s", pGE->port, strerror(errno)); Bye(EX_OSERR); } - ssocket = FileOpenFD(sfd, simpleSocket); - if ((CONSFILE *) 0 == ssocket) { - Error("Spawn(): FileOpenFD(%u): %s", sfd, strerror(errno)); - close(sfd); - Bye(EX_OSERR); - } - Kiddie(pGE, ssocket); + Kiddie(pGE, sfd); - /* should never get here... - */ - FileClose(&ssocket); - Error("Spawn(): internal flow error"); + /* should never get here...but on errors we could */ + close(sfd); Bye(EX_SOFTWARE); } diff --git a/conserver/group.h b/conserver/group.h index 383bf45..2a6108c 100644 --- a/conserver/group.h +++ b/conserver/group.h @@ -1,5 +1,5 @@ /* - * $Id: group.h,v 5.31 2003-03-17 08:43:20-08 bryan Exp $ + * $Id: group.h,v 5.38 2003-09-19 08:58:18-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -45,7 +45,6 @@ typedef struct grpent { /* group info */ unsigned short port; /* port group listens on */ pid_t pid; /* pid of server for group */ int imembers; /* number of consoles in this group */ - fd_set rinit; /* descriptor list */ CONSENT *pCElist; /* list of consoles in this group */ CONSENT *pCEctl; /* our control `console' */ CONSCLIENT *pCLall; /* all clients to scan after select */ @@ -55,10 +54,20 @@ typedef struct grpent { /* group info */ extern void Spawn PARAMS((GRPENT *)); extern int CheckPass PARAMS((char *, char *)); -extern void TagLogfile PARAMS((const CONSENT *, const char *, ...)); -extern void TagLogfileAct PARAMS((const CONSENT *, const char *, ...)); +extern void TagLogfile PARAMS((const CONSENT *, char *, ...)); +extern void TagLogfileAct PARAMS((const CONSENT *, char *, ...)); extern void CleanupBreak PARAMS((short)); extern void DestroyGroup PARAMS((GRPENT *)); extern void DestroyConsent PARAMS((GRPENT *, CONSENT *)); extern void SendClientsMsg PARAMS((CONSENT *, char *)); extern void ResetMark PARAMS((void)); +extern void DestroyConsentUsers PARAMS((CONSENTUSERS **)); +extern CONSENTUSERS *ConsentFindUser PARAMS((CONSENTUSERS *, char *)); +extern void DisconnectClient +PARAMS((GRPENT *, CONSCLIENT *, char *, FLAG)); +extern int ClientAccess PARAMS((CONSENT *, char *)); +extern void DestroyClient PARAMS((CONSCLIENT *)); +extern int CheckPasswd PARAMS((CONSCLIENT *, char *)); +#if HAVE_OPENSSL +extern int AttemptSSL PARAMS((CONSCLIENT *)); +#endif diff --git a/conserver/main.c b/conserver/main.c index 4083852..c2fea34 100644 --- a/conserver/main.c +++ b/conserver/main.c @@ -1,5 +1,5 @@ /* - * $Id: main.c,v 5.122 2003-04-06 05:31:13-07 bryan Exp $ + * $Id: main.c,v 5.157 2003-09-22 08:33:58-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -27,24 +27,11 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include - #include #include #include @@ -53,43 +40,39 @@ #include #include +#include +#if HAVE_SYS_SOCKIO_H +# include +#endif #if HAVE_OPENSSL -#include +# include #endif -int fAll = 0, fSoftcar = 0, fNoinit = 0, fVersion = 0, fStrip = - 0, fDaemon = 0, fUseLogfile = 0, fReopen = 0, fReopenall = - 0, fNoautoreup = 0, fNoredir = 0; +int fAll = 0, fNoinit = 0, fVersion = 0, fStrip = 0, fDaemon = 0, fReopen = + 0, fNoautoreup = 0, fSyntaxOnly = 0; char chDefAcc = 'r'; -char *pcLogfile = LOGFILEPATH; char *pcConfig = CONFIGFILE; -char *pcPasswd = PASSWDFILE; -char *pcPort = DEFPORT; -char *pcBasePort = DEFBASEPORT; -STRING *defaultShell = (STRING *) 0; -int domainHack = 0; int isMaster = 1; int cMaxMemb = MAXMEMB; -char *pcAddress = NULL; in_addr_t bindAddr; unsigned short bindPort; unsigned short bindBasePort; +static STRING *startedMsg = (STRING *)0; +CONFIG *optConf = (CONFIG *)0; +CONFIG *config = (CONFIG *)0; +char *interface = (char *)0; struct sockaddr_in in_port; -struct in_addr acMyAddr; -char acMyHost[1024]; /* staff.cc.purdue.edu */ #if HAVE_OPENSSL -SSL_CTX *ctx = (SSL_CTX *) 0; -int fReqEncryption = 1; -char *pcCredFile = (char *)0; -DH *dh512 = (DH *) 0; -DH *dh1024 = (DH *) 0; -DH *dh2048 = (DH *) 0; -DH *dh4096 = (DH *) 0; +SSL_CTX *ctx = (SSL_CTX *)0; +DH *dh512 = (DH *)0; +DH *dh1024 = (DH *)0; +DH *dh2048 = (DH *)0; +DH *dh4096 = (DH *)0; DH * @@ -292,7 +275,7 @@ GetDH4096() DH * #if PROTOTYPES -TmpDHCallback(SSL * ssl, int is_export, int keylength) +TmpDHCallback(SSL *ssl, int is_export, int keylength) #else TmpDHCallback(ssl, is_export, keylength) SSL *ssl; @@ -300,22 +283,23 @@ TmpDHCallback(ssl, is_export, keylength) int keylength; #endif { - Debug(1, "TmpDHCallback(): asked for a DH key length %u", keylength); + CONDDEBUG((1, "TmpDHCallback(): asked for a DH key length %u", + keylength)); switch (keylength) { case 512: - if (dh512 == (DH *) 0) + if (dh512 == (DH *)0) dh512 = GetDH512(); return dh512; case 1024: - if (dh1024 == (DH *) 0) + if (dh1024 == (DH *)0) dh1024 = GetDH1024(); return dh1024; case 2048: - if (dh2048 == (DH *) 0) + if (dh2048 == (DH *)0) dh2048 = GetDH2048(); return dh2048; default: - if (dh4096 == (DH *) 0) + if (dh4096 == (DH *)0) dh4096 = GetDH4096(); return dh4096; } @@ -328,13 +312,13 @@ SetupSSL(void) SetupSSL() #endif { - if (ctx == (SSL_CTX *) 0) { + if (ctx == (SSL_CTX *)0) { SSL_load_error_strings(); if (!SSL_library_init()) { Error("SetupSSL(): SSL_library_init() failed"); Bye(EX_SOFTWARE); } - if ((ctx = SSL_CTX_new(SSLv23_method())) == (SSL_CTX *) 0) { + if ((ctx = SSL_CTX_new(SSLv23_method())) == (SSL_CTX *)0) { Error("SetupSSL(): SSL_CTX_new() failed"); Bye(EX_SOFTWARE); } @@ -343,17 +327,19 @@ SetupSSL() ("SetupSSL(): could not load SSL default CA file and/or directory"); Bye(EX_SOFTWARE); } - 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 ("SetupSSL(): could not load SSL certificate from `%s'", - pcCredFile); + config->sslcredentials); Bye(EX_SOFTWARE); } if (SSL_CTX_use_PrivateKey_file - (ctx, pcCredFile, SSL_FILETYPE_PEM) != 1) { - Error("SetupSSL(): could not SSL private key from `%s'", - pcCredFile); + (ctx, config->sslcredentials, SSL_FILETYPE_PEM) != 1) { + Error + ("SetupSSL(): could not load SSL private key from `%s'", + config->sslcredentials); Bye(EX_SOFTWARE); } } @@ -386,22 +372,30 @@ ReopenLogfile(void) ReopenLogfile() #endif { + static int tag = 1; /* redirect stdout and stderr to the logfile. * * first time through any problems will show up (stderr still there). * after that, all bets are off...probably not see the errors (well, * aside from the tail of the old logfile, if it was rolled). */ - if (!fUseLogfile) + if (!fDaemon || config->logfile == (char *)0) return; close(1); - if (1 != open(pcLogfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) { - Error("ReopenLogfile(): open(%s): %s", pcLogfile, strerror(errno)); + if (1 != open(config->logfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) { + tag = 0; + Error("ReopenLogfile(): open(%s): %s", config->logfile, + strerror(errno)); Bye(EX_TEMPFAIL); } close(2); dup(1); + if (isMaster && tag) { + Msg("%s", THIS_VERSION); + Msg("%s", startedMsg->string); + } + tag = 0; } /* become a daemon (ksb) @@ -418,6 +412,7 @@ Daemonize() int td; #endif + Msg("daemonizing"); SimpleSignal(SIGQUIT, SIG_IGN); SimpleSignal(SIGINT, SIG_IGN); #if defined(SIGTTOU) @@ -453,7 +448,7 @@ Daemonize() #if HAVE_SETSID setsid(); #else - setpgrp(0, getpid()); + tcsetpgrp(0, getpid()); /* lose our controlling terminal */ @@ -476,7 +471,7 @@ Usage(wantfull) #endif { static char u_terse[] = - "[-7dDEFhinRouvV] [-a type] [-m max] [-M addr] [-p port] [-b port] [-c cred] [-C config] [-P passwd] [-L logfile] [-O min]"; + "[-7dDEFhinoRSuvV] [-a type] [-m max] [-M addr] [-p port] [-b port] [-c cred] [-C config] [-P passwd] [-L logfile] [-O min]"; static char *full[] = { "7 strip the high bit of all console data", "a type set the default access type", @@ -506,12 +501,13 @@ Usage(wantfull) "p port port to listen on", "P passwd give a new passwd file to the server process", "R disable automatic client redirection", + "S syntax check of configuration file", "u copy \"unloved\" console data to stdout", "v be verbose on startup", "V output version info", (char *)0 }; - fprintf(stderr, "%s: usage %s\n", progname, u_terse); + fprintf(stderr, "usage: %s %s\n", progname, u_terse); if (wantfull) { int i; for (i = 0; full[i] != (char *)0; i++) @@ -528,8 +524,8 @@ Version() Version() #endif { - static STRING *acA1 = (STRING *) 0; - static STRING *acA2 = (STRING *) 0; + static STRING *acA1 = (STRING *)0; + static STRING *acA2 = (STRING *)0; int i; char *optionlist[] = { #if HAVE_DMALLOC @@ -543,16 +539,13 @@ Version() #endif #if HAVE_PAM "pam", -#endif -#if HAVE_POSIX_REGCOMP - "regex", #endif (char *)0 }; - if (acA1 == (STRING *) 0) + if (acA1 == (STRING *)0) acA1 = AllocString(); - if (acA2 == (STRING *) 0) + if (acA2 == (STRING *)0) acA2 = AllocString(); isMultiProc = 0; @@ -561,57 +554,15 @@ Version() Msg("default access type `%c'", chDefAcc); Msg("default escape sequence `%s%s'", FmtCtl(DEFATTN, acA1), FmtCtl(DEFESC, acA2)); - Msg("configuration in `%s'", pcConfig); - Msg("password in `%s'", pcPasswd); - Msg("logfile is `%s'", pcLogfile); - Msg("pidfile is `%s'", PIDFILE); - Msg("limited to %d member%s per group", cMaxMemb, - cMaxMemb == 1 ? "" : "s"); + Msg("default configuration in `%s'", CONFIGFILE); + Msg("default password in `%s'", PASSWDFILE); + Msg("default logfile is `%s'", LOGFILEPATH); + Msg("default pidfile is `%s'", PIDFILE); + Msg("default limit is %d member%s per group", MAXMEMB, + MAXMEMB == 1 ? "" : "s"); + Msg("default primary port referenced as `%s'", DEFPORT); + Msg("default secondary base port referenced as `%s'", DEFBASEPORT); - /* Look for non-numeric characters */ - for (i = 0; pcPort[i] != '\000'; i++) - if (!isdigit((int)pcPort[i])) - break; - - if (pcPort[i] == '\000') { - /* numeric only */ - bindPort = atoi(pcPort); - Msg("on port %hu (referenced as `%s')", bindPort, pcPort); - } else { - /* non-numeric only */ - struct servent *pSE; - if ((struct servent *)0 == (pSE = getservbyname(pcPort, "tcp"))) { - Error("Version(): getservbyname(%s): %s", pcPort, - strerror(errno)); - } else { - bindPort = ntohs((unsigned short)pSE->s_port); - Msg("on port %hu (referenced as `%s')", bindPort, pcPort); - } - } - - /* Look for non-numeric characters */ - for (i = 0; pcBasePort[i] != '\000'; i++) - if (!isdigit((int)pcBasePort[i])) - break; - - if (pcBasePort[i] == '\000') { - /* numeric only */ - bindBasePort = atoi(pcBasePort); - Msg("secondary channel base port %hu (referenced as `%s')", - bindBasePort, pcBasePort); - } else { - /* non-numeric only */ - struct servent *pSE; - if ((struct servent *)0 == - (pSE = getservbyname(pcBasePort, "tcp"))) { - Error("Version(): getservbyname(%s): %s", pcBasePort, - strerror(errno)); - } else { - bindBasePort = ntohs((unsigned short)pSE->s_port); - Msg("secondary channel base port %hu (referenced as `%s')", - bindBasePort, pcBasePort); - } - } BuildString((char *)0, acA1); if (optionlist[0] == (char *)0) BuildString("none", acA1); @@ -658,39 +609,159 @@ DestroyDataStructures() REMOTE *pRC; ACCESS *pAC; - while (pGroups != (GRPENT *) 0) { + while (pGroups != (GRPENT *)0) { pGE = pGroups->pGEnext; DestroyGroup(pGroups); pGroups = pGE; } - while (pRCList != (REMOTE *) 0) { + while (pRCList != (REMOTE *)0) { pRC = pRCList->pRCnext; DestroyRemoteConsole(pRCList); pRCList = pRC; } - while (pACList != (ACCESS *) 0) { + while (pACList != (ACCESS *)0) { pAC = pACList->pACnext; DestroyAccessList(pACList); pACList = pAC; } + DestroyConsentUsers(&pADList); + + DestroyConfig(pConfig); + DestroyConfig(optConf); + DestroyConfig(config); #if HAVE_OPENSSL - if (ctx != (SSL_CTX *) 0) + if (ctx != (SSL_CTX *)0) SSL_CTX_free(ctx); - if (dh512 != (DH *) 0) + if (dh512 != (DH *)0) DH_free(dh512); - if (dh1024 != (DH *) 0) + if (dh1024 != (DH *)0) DH_free(dh1024); - if (dh2048 != (DH *) 0) + if (dh2048 != (DH *)0) DH_free(dh2048); - if (dh4096 != (DH *) 0) + if (dh4096 != (DH *)0) DH_free(dh4096); #endif + if (myAddrs != (struct in_addr *)0) + free(myAddrs); + DestroyBreakList(); DestroyStrings(); + DestroyUserList(); +} + +void +#if PROTOTYPES +SummarizeDataStructures(void) +#else +SummarizeDataStructures() +#endif +{ + GRPENT *pGE; + REMOTE *pRC; + ACCESS *pAC; + STRING *str; + CONSENT *pCE; + NAMES *usr; + int count; + long size; + long total = 0; + extern STRING *allStrings; + + if (!fDebug) + return; + + for (size = 0, count = 0, pGE = pGroups; pGE != (GRPENT *)0; + pGE = pGE->pGEnext, count++) { + size += sizeof(GRPENT); + } + CONDDEBUG((1, "Memory Usage (GRPENT objects): %ld (%d)", size, count)); + total += size; + + for (size = 0, count = 0, pGE = pGroups; pGE != (GRPENT *)0; + pGE = pGE->pGEnext) { + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; + pCE = pCE->pCEnext, count++) { + size += strlen(pCE->server) + sizeof(CONSENT); + if (pCE->host != (char *)0) + size += strlen(pCE->server); + if (pCE->device != (char *)0) + size += strlen(pCE->device); + if (pCE->exec != (char *)0) + size += strlen(pCE->exec); + if (pCE->master != (char *)0) + size += strlen(pCE->master); + if (pCE->logfile != (char *)0) + size += strlen(pCE->logfile); + if (pCE->execSlave != (char *)0) + size += strlen(pCE->execSlave); + if (pCE->fdlog != (CONSFILE *)0) + size += sizeof(CONSFILE); + if (pCE->cofile != (CONSFILE *)0) + size += sizeof(CONSFILE); + if (pCE->aliases != (NAMES *)0) { + NAMES *n; + for (n = pCE->aliases; n != (NAMES *)0; n = n->next) { + size += sizeof(NAMES) + strlen(n->name); + } + } + if (pCE->ro) { + CONSENTUSERS *u; + for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) { + size += sizeof(CONSENTUSERS) + strlen(u->user->name); + } + } + if (pCE->rw) { + CONSENTUSERS *u; + for (u = pCE->rw; u != (CONSENTUSERS *)0; u = u->next) { + size += sizeof(CONSENTUSERS) + strlen(u->user->name); + } + } + } + } + CONDDEBUG((1, "Memory Usage (CONSENT objects): %ld (%d)", size, + count)); + total += size; + + for (size = 0, count = 0, pRC = pRCList; pRC != (REMOTE *)0; + pRC = pRC->pRCnext, count++) { + size += strlen(pRC->rserver) + strlen(pRC->rhost) + sizeof(REMOTE); + if (pRC->aliases != (NAMES *)0) { + NAMES *n; + for (n = pRC->aliases; n != (NAMES *)0; n = n->next) { + size += sizeof(NAMES) + strlen(n->name); + } + } + } + CONDDEBUG((1, "Memory Usage (REMOTE objects): %ld (%d)", size, count)); + total += size; + + for (size = 0, count = 0, pAC = pACList; pAC != (ACCESS *)0; + pAC = pAC->pACnext, count++) { + size += strlen(pAC->pcwho) + sizeof(ACCESS); + } + CONDDEBUG((1, "Memory Usage (ACCESS objects): %ld (%d)", size, count)); + total += size; + + for (size = 0, count = 0, str = allStrings; str != (STRING *)0; + str = str->next, count++) { + size += str->allocated + sizeof(STRING); + } + CONDDEBUG((1, "Memory Usage (STRING objects): %ld (%d)", size, count)); + total += size; + + for (size = 0, count = 0, usr = userList; usr != (NAMES *)0; + usr = usr->next, count++) { + size += strlen(usr->name) + sizeof(NAMES); + } + CONDDEBUG((1, "Memory Usage (userList objects): %ld (%d)", size, + count)); + total += size; + + CONDDEBUG((1, "Memory Usage (total): %ld", total)); } void @@ -705,71 +776,289 @@ DumpDataStructures() REMOTE *pRC; char *empty = ""; +#define EMPTYSTR(x) x == (char *)0 ? empty : x if (!fDebug) return; - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { - Debug(1, - "DumpDataStructures(): group: id=%u pid=%lu, port=%hu, imembers=%d", - pGE->id, pGE->port, (unsigned long)pGE->pid, pGE->imembers); + SummarizeDataStructures(); - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; pCE = pCE->pCEnext) { - if (pCE->pccmd.string == (char *)0) - pCE->pccmd.string = empty; - if (pCE->server.string == (char *)0) - pCE->server.string = empty; - if (pCE->dfile.string == (char *)0) - pCE->dfile.string = empty; - if (pCE->lfile.string == (char *)0) - pCE->lfile.string = empty; - if (pCE->networkConsoleHost.string == (char *)0) - pCE->networkConsoleHost.string = empty; - if (pCE->acslave.string == (char *)0) - pCE->acslave.string = empty; + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { + CONDDEBUG((1, + "DumpDataStructures(): group: id=%u pid=%lu, port=%hu, imembers=%d", + pGE->id, pGE->port, (unsigned long)pGE->pid, + pGE->imembers)); - Debug(1, - "DumpDataStructures(): server=%s, dfile=%s, lfile=%s", - pCE->server.string, pCE->dfile.string, - pCE->lfile.string); - Debug(1, - "DumpDataStructures(): mark=%d, nextMark=%ld, breakType=%d", - pCE->mark, pCE->nextMark, pCE->breakType); + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { + switch (pCE->type) { + case DEVICE: + CONDDEBUG((1, + "DumpDataStructures(): server=%s, type=DEVICE", + EMPTYSTR(pCE->server))); + CONDDEBUG((1, + "DumpDataStructures(): baud=%s, parity=%s", + pCE->baud->acrate, pCE->parity->key)); + break; + case EXEC: + CONDDEBUG((1, + "DumpDataStructures(): server=%s, type=EXEC", + EMPTYSTR(pCE->server))); + CONDDEBUG((1, + "DumpDataStructures(): execSlave=%s, exec=%s, ipid=%lu", + EMPTYSTR(pCE->execSlave), + EMPTYSTR(pCE->exec), + (unsigned long)pCE->ipid)); - Debug(1, - "DumpDataStructures(): isNetworkConsole=%d, networkConsoleHost=%s", - pCE->isNetworkConsole, pCE->networkConsoleHost.string); - Debug(1, - "DumpDataStructures(): networkConsolePort=%hu, telnetState=%d, autoReup=%hu", - pCE->networkConsolePort, pCE->telnetState, - pCE->autoReUp); - - Debug(1, - "DumpDataStructures(): downHard=%hu, baud=%s, parity=%c", - pCE->downHard, pCE->pbaud->acrate, pCE->pparity->ckey); - - Debug(1, - "DumpDataStructures(): fvirtual=%d, acslave=%s, pccmd=%s, ipid=%lu", - pCE->fvirtual, pCE->acslave.string, pCE->pccmd.string, - (unsigned long)pCE->ipid); - - Debug(1, - "DumpDataStructures(): nolog=%d, fdtty=%d, activitylog=%d, breaklog=%d", - pCE->nolog, pCE->fdtty, pCE->activitylog, pCE->breaklog); - Debug(1, "DumpDataStructures(): fup=%d, fronly=%d", pCE->fup, - pCE->fronly); - Debug(1, "DumpDataStructures(): ------"); + break; + case HOST: + CONDDEBUG((1, + "DumpDataStructures(): server=%s, type=HOST", + EMPTYSTR(pCE->server))); + CONDDEBUG((1, + "DumpDataStructures(): host=%s, port=%hu, telnetState=%d", + EMPTYSTR(pCE->host), pCE->port, + pCE->telnetState)); + break; + case UNKNOWN: + CONDDEBUG((1, + "DumpDataStructures(): server=%s, type=UNKNOWN", + EMPTYSTR(pCE->server))); + break; + } + if (pCE->aliases != (NAMES *)0) { + NAMES *n; + for (n = pCE->aliases; n != (NAMES *)0; n = n->next) { + CONDDEBUG((1, "DumpDataStructures(): alias=%s", + n->name)); + } + } + CONDDEBUG((1, + "DumpDataStructures(): fup=%d, fronly=%d, logfile=%s, breakNum=%d", + pCE->fup, pCE->fronly, EMPTYSTR(pCE->logfile), + pCE->breakNum)); + CONDDEBUG((1, + "DumpDataStructures(): mark=%d, nextMark=%ld, autoReup=%hu, downHard=%s", + pCE->mark, pCE->nextMark, pCE->autoReUp, + pCE->downHard == FLAGTRUE ? "true" : "false")); + 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")); + CONDDEBUG((1, + "DumpDataStructures(): ixon=%s, ixany=%s, ixoff=%s", + pCE->ixon == FLAGTRUE ? "true" : "false", + pCE->ixany == FLAGTRUE ? "true" : "false", + pCE->ixoff == FLAGTRUE ? "true" : "false")); + 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")); +#if defined(CRTSCTS) + CONDDEBUG((1, "DumpDataStructures(): crtscts=%s", + pCE->crtscts == FLAGTRUE ? "true" : "false")); +#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")); + if (pCE->ro) { + CONSENTUSERS *u; + for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) { + CONDDEBUG((1, "DumpDataStructures(): ro=%s", + u->user->name)); + } + } + if (pCE->rw) { + CONSENTUSERS *u; + for (u = pCE->rw; u != (CONSENTUSERS *)0; u = u->next) { + CONDDEBUG((1, "DumpDataStructures(): rw=%s", + u->user->name)); + } + } + CONDDEBUG((1, "DumpDataStructures(): ------")); } } - for (pRC = pRCList; (REMOTE *) 0 != pRC; pRC = pRC->pRCnext) { - if (pRC->rserver.string == (char *)0) - pRC->rserver.string = empty; - if (pRC->rhost.string == (char *)0) - pRC->rhost.string = empty; - Debug(1, "DumpDataStructures(): remote: rserver=%s, rhost =%s", - pRC->rserver.string, pRC->rhost.string); + for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext) { + CONDDEBUG((1, "DumpDataStructures(): remote: rserver=%s, rhost=%s", + EMPTYSTR(pRC->rserver), EMPTYSTR(pRC->rhost))); + if (pRC->aliases != (NAMES *)0) { + NAMES *n; + for (n = pRC->aliases; n != (NAMES *)0; n = n->next) { + CONDDEBUG((1, "DumpDataStructures(): alias=%s", n->name)); + } + } } } +/* 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 ((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; + + 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 (bindAddr != INADDR_ANY) + count++; + if (count == 0) + return; + myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr)); + if (myAddrs == (struct in_addr *)0) + OutOfMem(); + if (bindAddr != INADDR_ANY) { + count--; +#if HAVE_MEMCPY + memcpy(&(myAddrs[count].s_addr), &bindAddr, sizeof(in_addr_t)); +#else + bcopy(&bindAddr, &(myAddrs[count].s_addr), sizeof(in_addr_t)); +#endif + Verbose("interface address %s (-M option)", + inet_ntoa(myAddrs[count])); + } + 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 +} + /* find out where/who we are (ksb) * parse optons * read in the config file, open the log file @@ -788,17 +1077,18 @@ main(argc, argv) #endif { int i; - FILE *fpConfig; - struct hostent *hpMe; - static char acOpts[] = "7a:b:c:C:dDEFhiL:m:M:noO:p:P:RsuVv"; + FILE *fpConfig = (FILE *)0; + static char acOpts[] = "7a:b:c:C:dDEFhiL:m:M:noO:p:P:RSuVv"; extern int optopt; extern char *optarg; struct passwd *pwd; char *origuser = (char *)0; char *curuser = (char *)0; - int curuid; - GRPENT *pGE; - CONSENT *pCE; + int curuid = 0; + GRPENT *pGE = (GRPENT *)0; +#if HAVE_INET_ATON + struct in_addr inetaddr; +#endif isMultiProc = 1; /* make sure stuff has the pid */ @@ -811,6 +1101,14 @@ main(argc, argv) setpwent(); + /* if we read from stdin (by accident) we don't wanna block. + * we just don't want any more input at this point. + */ + close(0); + if (0 != open("/dev/null", O_RDWR, 0644)) { + Error("open(/dev/null): %s", strerror(errno)); + Bye(EX_OSFILE); + } #if HAVE_SETLINEBUF setlinebuf(stdout); setlinebuf(stderr); @@ -820,22 +1118,13 @@ main(argc, argv) setvbuf(stderr, NULL, _IOLBF, BUFSIZ); #endif - - gethostname(acMyHost, sizeof(acMyHost)); - if ((struct hostent *)0 == (hpMe = gethostbyname(acMyHost))) { - Error("gethostbyname(%s): %s", acMyHost, hstrerror(h_errno)); - Bye(EX_TEMPFAIL); - } - if (4 != hpMe->h_length || AF_INET != hpMe->h_addrtype) { - Error("wrong address size (4 != %d) or adress family (%d != %d)", - hpMe->h_length, AF_INET, hpMe->h_addrtype); - Bye(EX_TEMPFAIL); - } -#if HAVE_MEMCPY - memcpy(&acMyAddr, hpMe->h_addr, hpMe->h_length); -#else - bcopy(hpMe->h_addr, &acMyAddr, hpMe->h_length); -#endif + /* prep the config options */ + if ((optConf = (CONFIG *)calloc(1, sizeof(CONFIG))) + == (CONFIG *)0) + OutOfMem(); + if ((config = (CONFIG *)calloc(1, sizeof(CONFIG))) + == (CONFIG *)0) + OutOfMem(); while (EOF != (i = getopt(argc, argv, acOpts))) { switch (i) { @@ -843,11 +1132,11 @@ main(argc, argv) fStrip = 1; break; case 'a': - chDefAcc = '\000' == *optarg ? 'r' : *optarg; - if (isupper((int)(chDefAcc))) { - chDefAcc = tolower(chDefAcc); - } - switch (chDefAcc) { + optConf->defaultaccess = *optarg; + if (isupper((int)(optConf->defaultaccess))) + optConf->defaultaccess = + tolower(optConf->defaultaccess); + switch (optConf->defaultaccess) { case 'r': case 'a': case 't': @@ -858,11 +1147,14 @@ main(argc, argv) } break; case 'b': - pcBasePort = optarg; + if ((optConf->secondaryport = strdup(optarg)) == (char *)0) + OutOfMem(); break; case 'c': #if HAVE_OPENSSL - pcCredFile = optarg; + if ((optConf->sslcredentials = + strdup(optarg)) == (char *)0) + OutOfMem(); #endif break; case 'C': @@ -870,14 +1162,13 @@ main(argc, argv) break; case 'd': fDaemon = 1; - fUseLogfile = 1; break; case 'D': fDebug++; break; case 'E': #if HAVE_OPENSSL - fReqEncryption = 0; + optConf->sslrequired = FLAGFALSE; #endif break; case 'F': @@ -890,13 +1181,19 @@ main(argc, argv) fNoinit = 1; break; case 'L': - pcLogfile = optarg; + if ((optConf->logfile = strdup(optarg)) == (char *)0) + OutOfMem(); break; case 'm': cMaxMemb = atoi(optarg); + if (cMaxMemb <= 0) { + Error("ignoring invalid -m option (%d <= 0)", + cMaxMemb); + cMaxMemb = MAXMEMB; + } break; case 'M': - pcAddress = optarg; + interface = optarg; break; case 'n': /* noop now */ @@ -907,19 +1204,21 @@ main(argc, argv) break; case 'O': /* How often to try opening all down consoles, in minutes */ - fReopenall = atoi(optarg); + optConf->reinitcheck = atoi(optarg); break; case 'p': - pcPort = optarg; + if ((optConf->primaryport = strdup(optarg)) == (char *)0) + OutOfMem(); break; case 'P': - pcPasswd = optarg; + if ((optConf->passwdfile = strdup(optarg)) == (char *)0) + OutOfMem(); break; case 'R': - fNoredir = 1; + optConf->redirect = FLAGFALSE; break; - case 's': - fSoftcar ^= 1; + case 'S': + fSyntaxOnly = 1; break; case 'u': fAll = 1; @@ -939,29 +1238,11 @@ main(argc, argv) } } - if (cMaxMemb <= 0) { - Error("ignoring invalid -m option (%d <= 0)", cMaxMemb); - cMaxMemb = MAXMEMB; - } - - /* if we read from stdin (by accident) we don't wanna block. - * we just don't want any more input at this point. - */ - close(0); - if (0 != open("/dev/null", O_RDWR, 0644)) { - Error("open(/dev/null): %s", strerror(errno)); - Bye(EX_OSFILE); - } - if (fVersion) { Version(); Bye(EX_OK); } - if (fDaemon) { - Daemonize(); - } - Msg("%s", THIS_VERSION); #if HAVE_GETLOGIN @@ -969,15 +1250,6 @@ main(argc, argv) #endif curuid = getuid(); - if (defaultShell == (STRING *) 0) - defaultShell = AllocString(); - if ((pwd = getpwuid(0)) != (struct passwd *)0 && - pwd->pw_shell[0] != '\000') { - BuildString(pwd->pw_shell, defaultShell); - } else { - BuildString("/bin/sh", defaultShell); - } - if ((struct passwd *)0 != (pwd = getpwuid(curuid))) curuser = pwd->pw_name; @@ -985,126 +1257,219 @@ main(argc, argv) if (curuser != (char *)0 && curuser[0] == '\000') curuser = (char *)0; + if (startedMsg == (STRING *)0) + startedMsg = AllocString(); if (curuser == (char *)0) if (origuser == (char *)0) - Msg("started as uid %d by uid %d", curuid, curuid); + BuildStringPrint(startedMsg, "started as uid %d by uid %d", + curuid, curuid); else - Msg("started as uid %d by `%s'", curuid, origuser); + BuildStringPrint(startedMsg, "started as uid %d by `%s'", + curuid, origuser); else - Msg("started as `%s' by `%s'", curuser, - (origuser == (char *)0) ? curuser : origuser); + BuildStringPrint(startedMsg, "started as `%s' by `%s'", curuser, + (origuser == (char *)0) ? curuser : origuser); endpwent(); + Msg("%s", startedMsg->string); #if HAVE_GETSPNAM && !HAVE_PAM - if (0 != geteuid()) { - Msg("Warning: running as a non-root user - any shadow password usage will most likely fail!"); + if (!fSyntaxOnly && (geteuid() != 0)) { + Msg("warning: running as a non-root user - any shadow password usage will most likely fail!"); } #endif - if (pcAddress == NULL) { + if (fSyntaxOnly) + Msg("performing configuration file syntax check"); + + /* set up the address to bind to */ + if (interface == (char *)0 || + (interface[0] == '*' && interface[1] == '\000')) bindAddr = INADDR_ANY; - } else { - bindAddr = inet_addr(pcAddress); - if (bindAddr == (in_addr_t) (-1)) { - Error("inet_addr(%s): %s", pcAddress, "invalid IP address"); + else { +#if HAVE_INET_ATON + if (inet_aton(interface, &inetaddr) == 0) { + Error("inet_aton(%s): %s", interface, "invalid IP address"); Bye(EX_OSERR); } - acMyAddr.s_addr = bindAddr; + bindAddr = inetaddr.s_addr; +#else + bindAddr = inet_addr(interface); + if (bindAddr == (in_addr_t) (-1)) { + Error("inet_addr(%s): %s", interface, "invalid IP address"); + Bye(EX_OSERR); + } +#endif } if (fDebug) { struct in_addr ba; ba.s_addr = bindAddr; - Debug(1, "main(): bind address set to `%s'", inet_ntoa(ba)); + CONDDEBUG((1, "main(): bind address set to `%s'", inet_ntoa(ba))); } - if (pcPort == NULL) { - Error - ("main(): severe error - pcPort is NULL???? how can that be?"); - Bye(EX_SOFTWARE); + /* must do all this so IsMe() works right */ + if (gethostname(myHostname, MAXHOSTNAME) != 0) { + Error("gethostname(): %s", interface, strerror(errno)); + Bye(EX_OSERR); } + ProbeInterfaces(); + + + /* read the config file */ + if ((FILE *)0 == (fpConfig = fopen(pcConfig, "r"))) { + Error("fopen(%s): %s", pcConfig, strerror(errno)); + Bye(EX_NOINPUT); + } + ReadCfg(pcConfig, fpConfig); + fclose(fpConfig); + + /* set up the port to bind to */ + if (optConf->primaryport != (char *)0) + config->primaryport = strdup(optConf->primaryport); + else if (pConfig->primaryport != (char *)0) + config->primaryport = strdup(pConfig->primaryport); + else + config->primaryport = strdup(DEFPORT); + if (config->primaryport == (char *)0) + OutOfMem(); /* Look for non-numeric characters */ - for (i = 0; pcPort[i] != '\000'; i++) - if (!isdigit((int)pcPort[i])) + for (i = 0; config->primaryport[i] != '\000'; i++) + if (!isdigit((int)config->primaryport[i])) break; - if (pcPort[i] == '\000') { + if (config->primaryport[i] == '\000') { /* numeric only */ - bindPort = atoi(pcPort); + bindPort = atoi(config->primaryport); } else { /* non-numeric only */ struct servent *pSE; - if ((struct servent *)0 == (pSE = getservbyname(pcPort, "tcp"))) { - Error("getservbyname(%s): %s", pcPort, strerror(errno)); + if ((struct servent *)0 == + (pSE = getservbyname(config->primaryport, "tcp"))) { + Error("getservbyname(%s): %s", config->primaryport, + strerror(errno)); Bye(EX_OSERR); } else { bindPort = ntohs((unsigned short)pSE->s_port); } } + /* set up the secondary port to bind to */ + if (optConf->secondaryport != (char *)0) + config->secondaryport = strdup(optConf->secondaryport); + else if (pConfig->secondaryport != (char *)0) + config->secondaryport = strdup(pConfig->secondaryport); + else + config->secondaryport = strdup(DEFBASEPORT); + if (config->secondaryport == (char *)0) + OutOfMem(); + /* Look for non-numeric characters */ - for (i = 0; pcBasePort[i] != '\000'; i++) - if (!isdigit((int)pcBasePort[i])) + for (i = 0; config->secondaryport[i] != '\000'; i++) + if (!isdigit((int)config->secondaryport[i])) break; - if (pcBasePort[i] == '\000') { + if (config->secondaryport[i] == '\000') { /* numeric only */ - bindBasePort = atoi(pcBasePort); + bindBasePort = atoi(config->secondaryport); } else { /* non-numeric only */ struct servent *pSE; if ((struct servent *)0 == - (pSE = getservbyname(pcBasePort, "tcp"))) { - Error("getservbyname(%s): %s", pcBasePort, strerror(errno)); + (pSE = getservbyname(config->secondaryport, "tcp"))) { + Error("getservbyname(%s): %s", config->secondaryport, + strerror(errno)); Bye(EX_OSERR); } else { bindBasePort = ntohs((unsigned short)pSE->s_port); } } - /* read the config file - */ - if ((FILE *) 0 == (fpConfig = fopen(pcConfig, "r"))) { - Error("fopen(%s): %s", pcConfig, strerror(errno)); - Bye(EX_NOINPUT); - } + if (optConf->passwdfile != (char *)0) + config->passwdfile = strdup(optConf->passwdfile); + else if (pConfig->passwdfile != (char *)0) + config->passwdfile = strdup(pConfig->passwdfile); + else + config->passwdfile = strdup(PASSWDFILE); + if (config->passwdfile == (char *)0) + OutOfMem(); - ReadCfg(pcConfig, fpConfig); + if (optConf->logfile != (char *)0) + config->logfile = strdup(optConf->logfile); + else if (pConfig->logfile != (char *)0) + config->logfile = strdup(pConfig->logfile); + else + config->logfile = strdup(LOGFILEPATH); + if (config->logfile == (char *)0) + OutOfMem(); - if (pGroups == (GRPENT *) 0 && pRCList == (REMOTE *) 0) { + if (optConf->reinitcheck != 0) + config->reinitcheck = optConf->reinitcheck; + else if (pConfig->reinitcheck != 0) + config->reinitcheck = pConfig->reinitcheck; + else + config->reinitcheck = 0; + + if (optConf->defaultaccess != '\000') + config->defaultaccess = optConf->defaultaccess; + else if (pConfig->defaultaccess != '\000') + config->defaultaccess = pConfig->defaultaccess; + else + config->defaultaccess = chDefAcc; + + if (optConf->redirect != FLAGUNKNOWN) + config->redirect = optConf->redirect; + else if (pConfig->redirect != FLAGUNKNOWN) + config->redirect = pConfig->redirect; + else + config->redirect = FLAGTRUE; + +#if HAVE_OPENSSL + if (optConf->sslrequired != FLAGUNKNOWN) + config->sslrequired = optConf->sslrequired; + else if (pConfig->sslrequired != FLAGUNKNOWN) + config->sslrequired = pConfig->sslrequired; + else + config->sslrequired = FLAGTRUE; + + if (optConf->sslcredentials != (char *)0) + config->sslcredentials = optConf->sslcredentials; + else if (pConfig->sslcredentials != (char *)0) + config->sslcredentials = pConfig->sslcredentials; + else + config->sslcredentials = (char *)0; +#endif + + if (pGroups == (GRPENT *)0 && pRCList == (REMOTE *)0) { Error("no consoles found in configuration file"); - } else { + } else if (!fSyntaxOnly) { #if HAVE_OPENSSL /* Prep the SSL layer */ SetupSSL(); #endif + if (fDaemon) + Daemonize(); + /* if no one can use us we need to come up with a default */ - if (pACList == (ACCESS *) 0) { - SetDefAccess(&acMyAddr, acMyHost); - } + if (pACList == (ACCESS *)0) + SetDefAccess(myAddrs, myHostname); /* spawn all the children, so fix kids has an initial pid */ - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { if (pGE->imembers == 0) continue; Spawn(pGE); Verbose("group #%d pid %lu on port %hu", pGE->id, - (unsigned long)pGE->pid, ntohs(pGE->port)); - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - if (-1 != pCE->fdtty) - close(pCE->fdtty); - } + (unsigned long)pGE->pid, pGE->port); } if (fVerbose) { ACCESS *pACtmp; - for (pACtmp = pACList; pACtmp != (ACCESS *) 0; + for (pACtmp = pACList; pACtmp != (ACCESS *)0; pACtmp = pACtmp->pACnext) { Verbose("access type `%c' for `%s'", pACtmp->ctrust, pACtmp->pcwho); @@ -1112,12 +1477,13 @@ main(argc, argv) } pRCUniq = FindUniq(pRCList); + /* output unique console server peers? */ if (fVerbose) { REMOTE *pRC; - for (pRC = pRCUniq; (REMOTE *) 0 != pRC; pRC = pRC->pRCuniq) { - Verbose("peer server on `%s'", pRC->rhost.string); + for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { + Verbose("peer server on `%s'", pRC->rhost); } } @@ -1135,7 +1501,9 @@ main(argc, argv) Msg("terminated"); endpwent(); - fclose(fpConfig); - Bye(EX_OK); + if (fSyntaxOnly && fErrorPrinted) + Bye(EX_DATAERR); + else + Bye(EX_OK); return EX_OK; /* never gets here clears the compiler warning */ } diff --git a/conserver/main.h b/conserver/main.h index 004eed4..404b12c 100644 --- a/conserver/main.h +++ b/conserver/main.h @@ -1,5 +1,5 @@ /* - * $Id: main.h,v 5.45 2003-03-09 15:20:43-08 bryan Exp $ + * $Id: main.h,v 5.49 2003-06-15 19:50:28-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -37,24 +37,18 @@ /* program options and stuff */ extern char rcsid[]; -extern int fAll, fSoftcar, fNoinit, fInteractive, fStrip, fDaemon, fReopen, - fReopenall, fNoautoreup, fNoredir; -extern char chDefAcc; +extern int fAll, fNoinit, fInteractive, fStrip, fDaemon, fReopen, + fNoautoreup, fSyntaxOnly; extern in_addr_t bindAddr; extern unsigned short bindPort, bindBasePort; -extern char *pcLogfile; extern char *pcConfig; -extern char *pcPasswd; -extern STRING *defaultShell; extern int cMaxMemb; extern struct sockaddr_in in_port; -extern char acMyHost[]; -extern struct in_addr acMyAddr; -extern int domainHack; extern int isMaster; +extern CONFIG *optConf; +extern CONFIG *config; #if HAVE_OPENSSL extern SSL_CTX *ctx; -extern int fReqEncryption; #endif extern void ReopenLogfile PARAMS((void)); extern void DumpDataStructures PARAMS((void)); diff --git a/conserver/master.c b/conserver/master.c index 73e3cde..15e7fa6 100644 --- a/conserver/master.c +++ b/conserver/master.c @@ -1,5 +1,5 @@ /* - * $Id: master.c,v 5.94 2003-04-07 18:48:12-07 bryan Exp $ + * $Id: master.c,v 5.113 2003-09-19 08:58:18-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -26,23 +26,10 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include #include #include #include @@ -52,16 +39,13 @@ #include #include -#if defined(USE_LIBWRAP) -#include -#include -int allow_severity = LOG_INFO; -int deny_severity = LOG_WARNING; -#endif - static sig_atomic_t fSawQuit = 0, fSawHUP = 0, fSawUSR2 = 0, fSawUSR1 = 0, fSawCHLD = 0; +static CONSCLIENT *pCLfree = (CONSCLIENT *)0; +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION +static unsigned long dmallocMarkClientConnection = 0; +#endif static RETSIGTYPE @@ -102,7 +86,7 @@ FixKids() continue; } - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { if (0 == pGE->imembers) continue; if (pid != pGE->pid) @@ -139,7 +123,7 @@ FixKids() */ Spawn(pGE); Verbose("group #%d pid %lu on port %hu", pGE->id, - (unsigned long)pGE->pid, ntohs(pGE->port)); + (unsigned long)pGE->pid, pGE->port); } } } @@ -232,11 +216,11 @@ SignalKids(arg) { GRPENT *pGE; - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { if (0 == pGE->imembers || -1 == pGE->pid) continue; - Debug(1, "SignalKids(): sending pid %lu signal %d", - (unsigned long)pGE->pid, arg); + CONDDEBUG((1, "SignalKids(): sending pid %lu signal %d", + (unsigned long)pGE->pid, arg)); if (-1 == kill(pGE->pid, arg)) { Error("SignalKids(): kill(%lu): %s", (unsigned long)pGE->pid, strerror(errno)); @@ -244,6 +228,378 @@ SignalKids(arg) } } +void +#if PROTOTYPES +CommandCall(CONSCLIENT *pCL, char *args) +#else +CommandCall(pCL, args) + CONSCLIENT *pCL; + char *args; +#endif +{ + int found; + REMOTE *pRC, *pRCFound; + unsigned short prnum = 0; + char *ambiguous = (char *)0; + CONSENT *pCE; + GRPENT *pGE; + + found = 0; + pRCFound = (REMOTE *)0; + ambiguous = BuildTmpString((char *)0); + /* look for a local machine */ + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { + if (pGE->imembers == 0) + continue; + if ((pCE = FindConsoleName(pGE->pCElist, args)) != (CONSENT *)0) { + prnum = pGE->port; + ambiguous = BuildTmpString(pCE->server); + ambiguous = BuildTmpString(", "); + ++found; + } + } + if (found == 0) { /* Then look for substring matches */ + NAMES *name = (NAMES *)0; + int foundOne = 0; + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { + if (0 == pGE->imembers) + continue; + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; + pCE = pCE->pCEnext) { + foundOne = 0; + if (strncasecmp(args, pCE->server, strlen(args)) == 0) { + prnum = pGE->port; + ambiguous = BuildTmpString(pCE->server); + ambiguous = BuildTmpString(", "); + ++foundOne; + } + for (name = pCE->aliases; name != (NAMES *)0; + name = name->next) { + if (strncasecmp(args, name->name, strlen(args)) + != 0) + continue; + prnum = pGE->port; + ambiguous = BuildTmpString(name->name); + ambiguous = BuildTmpString(", "); + ++foundOne; + } + if (foundOne) + ++found; + } + } + /* look for a remote server if redirect is enabled or if + * redirect is not enabled and we haven't found a unique + * console match */ + if (config->redirect == FLAGTRUE || + (config->redirect != FLAGTRUE && found != 1)) { + for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext) { + foundOne = 0; + if (strncasecmp(args, pRC->rserver, strlen(args)) + == 0) { + pRCFound = pRC; + ambiguous = BuildTmpString(pRC->rserver); + ambiguous = BuildTmpString(", "); + ++foundOne; + } + for (name = pRC->aliases; name != (NAMES *)0; + name = name->next) { + if (strncasecmp(args, name->name, strlen(args)) + != 0) + continue; + pRCFound = pRC; + ambiguous = BuildTmpString(name->name); + ambiguous = BuildTmpString(", "); + ++foundOne; + } + if (foundOne) + ++found; + } + } + } + switch (found) { + case 0: + FilePrint(pCL->fd, "console `%s' not found\r\n", args); + break; + case 1: + if ((REMOTE *)0 != pRCFound) { + if (config->redirect != FLAGTRUE) { + FilePrint(pCL->fd, + "automatic redirection disabled - console on master `%s'\r\n", + pRCFound->rhost); + } else { + FilePrint(pCL->fd, "@%s\r\n", pRCFound->rhost); + } + } else { + FilePrint(pCL->fd, "%hu\r\n", prnum); + } + break; + default: + found = strlen(ambiguous); + ambiguous[found - 2] = '\000'; + FilePrint(pCL->fd, + "ambiguous console abbreviation, `%s'\r\n\tchoices are %s\r\n", + args, ambiguous); + break; + } + BuildTmpString((char *)0); /* we're done - clean up */ + ambiguous = (char *)0; +} + +void +#if PROTOTYPES +DropMasterClient(CONSCLIENT *pCLServing, FLAG force) +#else +DropMasterClient(pCLServing, force) + CONSCLIENT *pCLServing; + FLAG force; +#endif +{ + /* if we have data buffered and aren't forced to close, + * we can't close quite yet + */ + if (force != FLAGTRUE && !FileBufEmpty(pCLServing->fd)) { + pCLServing->ioState = ISFLUSHING; + return; + } + + if (pCLServing->iState == S_NORMAL) + Verbose(" logout %s", pCLServing->acid->string); + + /* drop a connection */ + FD_CLR(FileFDNum(pCLServing->fd), &rinit); + FD_CLR(FileFDNum(pCLServing->fd), &winit); + FileClose(&pCLServing->fd); + pCLServing->ioState = ISDISCONNECTED; + + /* remove from the "all" list */ + if ((CONSCLIENT *)0 != pCLServing->pCLscan) { + pCLServing->pCLscan->ppCLbscan = pCLServing->ppCLbscan; + } + *(pCLServing->ppCLbscan) = pCLServing->pCLscan; + /* put on the free list */ + pCLServing->pCLnext = pCLfree; + pCLfree = pCLServing; + + /* we didn't touch pCLServing->pCLscan so the loop works */ +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION + CONDDEBUG((1, "Master(): dmalloc / MarkClientConnection")); + dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); +#endif +} + +void +#if PROTOTYPES +DoNormalRead(CONSCLIENT *pCLServing) +#else +DoNormalRead(pCLServing) + CONSCLIENT *pCLServing; +#endif +{ + char *pcCmd; + char *pcArgs; + int nr, i; + unsigned char acIn[BUFSIZ]; + + /* read connection */ + if ((nr = FileRead(pCLServing->fd, acIn, sizeof(acIn))) < 0) { + DropMasterClient(pCLServing, FLAGFALSE); + return; + } + + for (i = 0; i < nr; ++i) { + if ('\n' != acIn[i]) { + BuildStringChar(acIn[i], pCLServing->accmd); + continue; + } + if ((pCLServing->accmd->used > 1) && + ('\r' == + pCLServing->accmd->string[pCLServing->accmd->used - 2])) { + pCLServing->accmd->string[pCLServing->accmd->used - 2] = + '\000'; + pCLServing->accmd->used--; + } + + /* process password here...before we corrupt accmd */ + if (pCLServing->iState == S_PASSWD) { + if (CheckPasswd(pCLServing, pCLServing->accmd->string) != + AUTH_SUCCESS) { + FileWrite(pCLServing->fd, "invalid password\r\n", -1); + BuildString((char *)0, pCLServing->accmd); + DropMasterClient(pCLServing, FLAGFALSE); + return; + } + Verbose(" login %s", pCLServing->acid->string); + FileWrite(pCLServing->fd, "ok\r\n", -1); + pCLServing->iState = S_NORMAL; + BuildString((char *)0, pCLServing->accmd); + continue; + } + + if ((char *)0 != (pcArgs = strchr(pCLServing->accmd->string, ':'))) { + *pcArgs++ = '\000'; + } else if ((char *)0 != + (pcArgs = strchr(pCLServing->accmd->string, ' '))) { + *pcArgs++ = '\000'; + } + if (pcArgs != (char *)0) + pcArgs = PruneSpace(pcArgs); + pcCmd = PruneSpace(pCLServing->accmd->string); + if (strcmp(pcCmd, "help") == 0) { + static char *apcHelp1[] = { + "exit disconnect\r\n", + "help this help message\r\n", + "login log in\r\n", +#if HAVE_OPENSSL + "ssl start ssl session\r\n", +#endif + (char *)0 + }; + static char *apcHelp2[] = { + "call provide port for given console\r\n", + "exit disconnect\r\n", + "groups provide ports for group leaders\r\n", + "help this help message\r\n", + "master provide a list of master servers\r\n", + "pid provide pid of master process\r\n", + "quit* terminate conserver (SIGTERM)\r\n", + "restart* restart conserver (SIGHUP)\r\n", + "version provide version info for server\r\n", + "* = requires admin privileges\r\n", + (char *)0 + }; + char **ppc; + for (ppc = + (pCLServing->iState == S_IDENT ? apcHelp1 : apcHelp2); + (char *)0 != *ppc; ++ppc) { + FileWrite(pCLServing->fd, *ppc, -1); + } + } else if (strcmp(pcCmd, "exit") == 0) { + FileWrite(pCLServing->fd, "goodbye\r\n", -1); + DropMasterClient(pCLServing, FLAGFALSE); + return; +#if HAVE_OPENSSL + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "ssl") == 0) { + FileWrite(pCLServing->fd, "ok\r\n", -1); + if (!AttemptSSL(pCLServing)) { + DropMasterClient(pCLServing, FLAGFALSE); + return; + } +#endif + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "login") == 0) { +#if HAVE_OPENSSL + if (config->sslrequired == FLAGTRUE && + FileGetType(pCLServing->fd) != SSLSocket) { + FileWrite(pCLServing->fd, "encryption required\r\n", -1); + } else { +#endif + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, + "login requires argument\r\n", -1); + } else { + BuildString((char *)0, pCLServing->username); + BuildString((char *)0, pCLServing->acid); + BuildString(pcArgs, pCLServing->username); + BuildString(pcArgs, pCLServing->acid); + BuildStringChar('@', pCLServing->acid); + BuildString(pCLServing->peername->string, + pCLServing->acid); + if (pCLServing->caccess == 't' || + CheckPasswd(pCLServing, "") == AUTH_SUCCESS) { + pCLServing->iState = S_NORMAL; + Verbose(" login %s", + pCLServing->acid->string); + FileWrite(pCLServing->fd, "ok\r\n", -1); + } else { + FileWrite(pCLServing->fd, "passwd?\r\n", -1); + pCLServing->iState = S_PASSWD; + } + } +#if HAVE_OPENSSL + } +#endif + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "master") == 0) { + int iSep = 1; + + if ((GRPENT *)0 != pGroups) { + struct sockaddr_in lcl; + socklen_t so = sizeof(lcl); + if (-1 == + getsockname(FileFDNum(pCLServing->fd), + (struct sockaddr *)&lcl, &so)) { + FileWrite(pCLServing->fd, + "getsockname failed, try again later\r\n", + -1); + Error("Master(): getsockname(%u): %s", + FileFDNum(pCLServing->fd), strerror(errno)); + Bye(EX_OSERR); + } + FilePrint(pCLServing->fd, "@%s", inet_ntoa(lcl.sin_addr)); + iSep = 0; + } + if (config->redirect == FLAGTRUE) { + REMOTE *pRC; + for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { + FilePrint(pCLServing->fd, ":@%s" + iSep, pRC->rhost); + iSep = 0; + } + } + FileWrite(pCLServing->fd, "\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "pid") == 0) { + FilePrint(pCLServing->fd, "%lu\r\n", (unsigned long)thepid); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "version") == 0) { + FilePrint(pCLServing->fd, "version `%s'\r\n", THIS_VERSION); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "quit") == 0) { + if (ConsentFindUser(pADList, pCLServing->username->string) != + (CONSENTUSERS *)0 || + ConsentFindUser(pADList, "*") != (CONSENTUSERS *)0) { + Verbose("quit command by %s", pCLServing->acid->string); + FileWrite(pCLServing->fd, "ok -- terminated\r\n", -1); + DropMasterClient(pCLServing, FLAGFALSE); + kill(thepid, SIGTERM); + return; + } else + FileWrite(pCLServing->fd, "unauthorized command\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "restart") == 0) { + if (ConsentFindUser(pADList, pCLServing->username->string) != + (CONSENTUSERS *)0 || + ConsentFindUser(pADList, "*") != (CONSENTUSERS *)0) { + FileWrite(pCLServing->fd, "ok -- restarting\r\n", -1); + Verbose("restart command by %s", pCLServing->acid->string); + kill(thepid, SIGHUP); + } else + FileWrite(pCLServing->fd, "unauthorized command\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "groups") == 0) { + int iSep = 1; + GRPENT *pGE; + + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { + if (0 == pGE->imembers) + continue; + FilePrint(pCLServing->fd, ":%hu" + iSep, pGE->port); + iSep = 0; + } + FileWrite(pCLServing->fd, "\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "call") == 0) { + if (pcArgs == (char *)0) + FileWrite(pCLServing->fd, "call requires argument\r\n", + -1); + else + CommandCall(pCLServing, pcArgs); + } else { + FileWrite(pCLServing->fd, "unknown command\r\n", -1); + } + BuildString((char *)0, pCLServing->accmd); + } +} /* this routine is used by the master console server process (ksb) */ @@ -254,24 +610,16 @@ Master(void) Master() #endif { - char *pcArgs; - int i, j, cfd; - CONSFILE *csocket; - REMOTE *pRC, *pRCFound; - int nr, found, msfd; - unsigned short prnum = 0; - struct hostent *hpPeer; - char cType; + int cfd; + int msfd; socklen_t so; - fd_set rmask, rmaster; - unsigned char acIn[1024]; /* a command to the master is limited to this */ - struct sockaddr_in master_port, response_port; + fd_set rmask, wmask; + struct sockaddr_in master_port; int true = 1; - pid_t pid, parentpid; - char *ambiguous = (char *)0; - GRPENT *pGE; - CONSENT *pCE; FILE *fp; + CONSCLIENT *pCLServing = (CONSCLIENT *)0; + CONSCLIENT *pCL = (CONSCLIENT *)0; + CONSCLIENT *pCLall = (CONSCLIENT *)0; /* set up signal handler */ @@ -293,6 +641,15 @@ Master() SimpleSignal(SIGUSR2, FlagSawUSR2); SimpleSignal(SIGINT, FlagSawINT); + /* prime the free connection slots */ + if ((pCLfree = (CONSCLIENT *)calloc(1, sizeof(CONSCLIENT))) + == (CONSCLIENT *)0) + OutOfMem(); + pCLfree->accmd = AllocString(); + pCLfree->peername = AllocString(); + pCLfree->username = AllocString(); + pCLfree->acid = AllocString(); + /* set up port for master to listen on */ #if HAVE_MEMSET @@ -318,13 +675,19 @@ Master() return; } #endif + + if (!SetFlags(msfd, O_NONBLOCK, 0)) + return; + if (bind(msfd, (struct sockaddr *)&master_port, sizeof(master_port)) < 0) { - Error("Master(): bind(%u): %s", msfd, strerror(errno)); + Error("Master(): bind(%hu): %s", ntohs(master_port.sin_port), + strerror(errno)); return; } if (listen(msfd, SOMAXCONN) < 0) { - Error("Master(): listen(%u): %s", msfd, strerror(errno)); + Error("Master(): listen(%hu): %s", ntohs(master_port.sin_port), + strerror(errno)); return; } @@ -333,11 +696,13 @@ Master() fprintf(fp, "%lu\n", (unsigned long)getpid()); fclose(fp); } else { - Error("Master(): can't write pid to %s", PIDFILE); + Error("Master(): can't write pid to %s: %s", PIDFILE, + strerror(errno)); } - FD_ZERO(&rmaster); - FD_SET(msfd, &rmaster); + FD_ZERO(&rinit); + FD_SET(msfd, &rinit); + maxfd = msfd + 1; for (fSawQuit = 0; !fSawQuit; /* can't close here :-( */ ) { if (fSawCHLD) { @@ -349,7 +714,16 @@ Master() Msg("processing SIGHUP"); ReopenLogfile(); SignalKids(SIGHUP); - ReReadCfg(); + ReReadCfg(msfd); + /* fix up the client descriptors since ReReadCfg() doesn't + * see them like it can in the child processes */ + for (pCL = pCLall; pCL != (CONSCLIENT *)0; pCL = pCL->pCLscan) { + FD_SET(FileFDNum(pCL->fd), &rinit); + if (maxfd < FileFDNum(pCL->fd) + 1) + maxfd = FileFDNum(pCL->fd) + 1; + if (!FileBufEmpty(pCL->fd)) + FD_SET(FileFDNum(pCL->fd), &winit); + } } if (fSawUSR1) { fSawUSR1 = 0; @@ -366,324 +740,150 @@ Master() break; } - rmask = rmaster; + rmask = rinit; + wmask = winit; if (-1 == - select(msfd + 1, &rmask, (fd_set *) 0, (fd_set *) 0, + select(maxfd, &rmask, &wmask, (fd_set *)0, (struct timeval *)0)) { if (errno != EINTR) { Error("Master(): select(): %s", strerror(errno)); + break; } continue; } - if (!FD_ISSET(msfd, &rmask)) { - continue; + + /* anything on a connection? */ + for (pCLServing = pCLall; (CONSCLIENT *)0 != pCLServing; + pCLServing = pCLServing->pCLscan) { + switch (pCLServing->ioState) { +#if HAVE_OPENSSL + case INSSLACCEPT: + if (FileCanSSLAccept(pCLServing->fd, &rmask, &wmask)) { + int r; + if ((r = FileSSLAccept(pCLServing->fd)) < 0) + DropMasterClient(pCLServing, FLAGFALSE); + else if (r == 1) + pCLServing->ioState = ISNORMAL; + } + break; +#endif + case ISNORMAL: + if (FileCanRead(pCLServing->fd, &rmask, &wmask)) + DoNormalRead(pCLServing); + /* fall through to ISFLUSHING for buffered data */ + case ISFLUSHING: + if (!FileBufEmpty(pCLServing->fd) && + FileCanWrite(pCLServing->fd, &rmask, &wmask)) { + CONDDEBUG((1, "Master(): flushing fd %d", + FileFDNum(pCLServing->fd))); + if (FileWrite(pCLServing->fd, (char *)0, 0) < 0) { + DropMasterClient(pCLServing, FLAGTRUE); + break; + } + } + if ((pCLServing->ioState == ISFLUSHING) && + FileBufEmpty(pCLServing->fd)) + DropMasterClient(pCLServing, FLAGFALSE); + break; + default: + /* this really can't ever happen */ + Error + ("Master(): client socket state == %d -- THIS IS A BUG", + pCLServing->ioState); + DropMasterClient(pCLServing, FLAGFALSE); + break; + } + } + + /* if nothing on control line, get more */ + if (!FD_ISSET(msfd, &rmask)) + continue; + + /* accept new connections and deal with them + */ +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION + dmallocMarkClientConnection = dmalloc_mark(); +#endif + + so = sizeof(struct sockaddr_in); + for (cfd = 0; cfd == 0;) { + cfd = + accept(msfd, (struct sockaddr *)&pCLfree->cnct_port, &so); + if (cfd < 0 && errno == EINTR) + cfd = 0; } - so = sizeof(response_port); - cfd = accept(msfd, (struct sockaddr *)&response_port, &so); if (cfd < 0) { Error("Master(): accept(%u): %s", msfd, strerror(errno)); +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION + CONDDEBUG((1, "Master(): dmalloc / MarkClientConnection")); + dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); +#endif continue; } - if ((CONSFILE *) 0 == (csocket = FileOpenFD(cfd, simpleSocket))) { + /* set to non-blocking and wrap in a File object */ + if (SetFlags(cfd, O_NONBLOCK, 0)) + pCLfree->fd = FileOpenFD(cfd, simpleSocket); + else + pCLfree->fd = (CONSFILE *)0; + + if ((CONSFILE *)0 == pCLfree->fd) { Error("Master(): FileOpenFD(%u): %s", cfd, strerror(errno)); - close(cfd); - continue; - } -#if defined(USE_LIBWRAP) - { - struct request_info request; - request_init(&request, RQ_DAEMON, progname, RQ_FILE, cfd, 0); - fromhost(&request); - if (!hosts_access(&request)) { - FileWrite(csocket, "access from your host refused\r\n", - -1); - FileClose(&csocket); - continue; - } - } +#if HAVE_DMALLOC && DMALLOC_MARK_CLIENT_CONNECTION + CONDDEBUG((1, "Master(): dmalloc / MarkClientConnection")); + dmalloc_log_changed(dmallocMarkClientConnection, 1, 0, 1); #endif - - so = sizeof(in_port); - if (-1 == - getpeername(FileFDNum(csocket), (struct sockaddr *)&in_port, - &so)) { - FileWrite(csocket, "getpeername failed\r\n", -1); - FileClose(&csocket); - continue; - } - so = sizeof(in_port.sin_addr); - if ((struct hostent *)0 == - (hpPeer = - gethostbyaddr((char *)&in_port.sin_addr, so, AF_INET))) { - cType = AccType(&in_port.sin_addr, NULL); - } else { - cType = AccType(&in_port.sin_addr, hpPeer->h_name); - } - if ('r' == cType) { - FileWrite(csocket, "access from your host refused\r\n", -1); - FileClose(&csocket); continue; } - fflush(stdin); - fflush(stderr); - switch (pid = fork()) { - case -1: - FileWrite(csocket, "fork failed, try again later\r\n", -1); - FileClose(&csocket); - Error("Master(): fork(): %s", strerror(errno)); - continue; - default: -#if defined(__CYGWIN__) - /* Since we've got all that "special" stuff in the FileClose - * routine for getting around a winsock bug, we have to - * shut things down differently here. Instead of calling - * FileClose (which half-closes the socket as well as just - * closing the descriptor), we "unopen" the structure (to - * free memory) and then do a regular close. The child (which - * writes to the client) will do a FileClose and all the - * flushing magic will happen. UGH! -bryan - */ - close(FileUnopen(csocket)); -#else - FileClose(&csocket); -#endif - continue; - case 0: - parentpid = thepid; - thepid = getpid(); - break; + /* remove from the free list */ + pCL = pCLfree; + pCLfree = pCL->pCLnext; + + /* add another if we ran out */ + if (pCLfree == (CONSCLIENT *)0) { + if ((pCLfree = (CONSCLIENT *)calloc(1, sizeof(CONSCLIENT))) + == (CONSCLIENT *)0) + OutOfMem(); + pCLfree->accmd = AllocString(); + pCLfree->peername = AllocString(); + pCLfree->username = AllocString(); + pCLfree->acid = AllocString(); } - /* handle the connection - * (port lookup, who, users, or quit) - */ - FileWrite(csocket, "ok\r\n", -1); - for (i = 0; i < sizeof(acIn) - 1; /* i+=nr */ ) { - if ((nr = - FileRead(csocket, &acIn[i], sizeof(acIn) - 1 - i)) <= 0) { - break; - } - for (j = 0; j < nr; j++, i++) { - if (acIn[i] == '\n') { - acIn[i] = '\000'; - if (i > 0 && acIn[i - 1] == '\r') - acIn[--i] = '\000'; - break; - } - } - if (j != nr) - break; - acIn[i] = '\000'; + /* link into all clients list */ + pCL->pCLscan = pCLall; + pCL->ppCLbscan = &pCLall; + if ((CONSCLIENT *)0 != pCL->pCLscan) { + pCL->pCLscan->ppCLbscan = &pCL->pCLscan; } - if (0 == i) { - Error("Master(): lost connection (%u)", FileFDNum(csocket)); - FileClose(&csocket); - Bye(EX_OK); - } - if ((char *)0 != (pcArgs = strchr((char *)acIn, ':'))) { - *pcArgs++ = '\000'; - } else if ((char *)0 != (pcArgs = strchr((char *)acIn, ' '))) { - *pcArgs++ = '\000'; - } - if (0 == strcmp((char *)acIn, "help")) { - static char *apcHelp[] = { - "call provide port for given machine\r\n", - "groups provide ports for group leaders\r\n", - "help this help message\r\n", - "master provide a list of master servers\r\n", - "pid provide pid of master process\r\n", - "quit terminate conserver\r\n", - "version provide version info for server\r\n", - (char *)0 - }; - char **ppc; - for (ppc = apcHelp; (char *)0 != *ppc; ++ppc) { - FileWrite(csocket, *ppc, -1); - } - FileClose(&csocket); - Bye(EX_OK); - } - if (0 == strcmp((char *)acIn, "quit")) { - if ('t' == cType) { - FileWrite(csocket, "trusted -- terminated\r\n", -1); - kill(parentpid, SIGTERM); - } else if ((char *)0 == pcArgs) { - FileWrite(csocket, "must be trusted to terminate\r\n", -1); - } else if (CheckPass("root", pcArgs) != AUTH_SUCCESS) { - FileWrite(csocket, "Sorry.\r\n", -1); - } else { - FileWrite(csocket, "ok -- terminated\r\n", -1); - kill(parentpid, SIGTERM); - } - FileClose(&csocket); - Bye(EX_OK); - } - if (0 == strcmp((char *)acIn, "pid")) { - FilePrint(csocket, "%lu\r\n", (unsigned long)parentpid); - FileClose(&csocket); - Bye(EX_OK); - } - if (0 == strcmp((char *)acIn, "groups")) { - int iSep = 1; + pCLall = pCL; - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { - if (0 == pGE->imembers) - continue; - FilePrint(csocket, ":%hu" + iSep, ntohs(pGE->port)); - iSep = 0; - } - FileWrite(csocket, "\r\n", -1); - FileClose(&csocket); - Bye(EX_OK); - } - if (0 == strcmp((char *)acIn, "master")) { - int iSep = 1; + FD_SET(cfd, &rinit); + if (maxfd < cfd + 1) + maxfd = cfd + 1; - if ((GRPENT *) 0 != pGroups) { - struct sockaddr_in lcl; - so = sizeof(lcl); - if (-1 == - getsockname(FileFDNum(csocket), - (struct sockaddr *)&lcl, &so)) { - FileWrite(csocket, - "getsockname failed, try again later\r\n", - -1); - Error("Master(): getsockname(%u): %s", - FileFDNum(csocket), strerror(errno)); - Bye(EX_OSERR); - } - FilePrint(csocket, "@%s", inet_ntoa(lcl.sin_addr)); - iSep = 0; - } - if (!fNoredir) { - for (pRC = pRCUniq; (REMOTE *) 0 != pRC; - pRC = pRC->pRCuniq) { - FilePrint(csocket, ":@%s" + iSep, pRC->rhost.string); - iSep = 0; - } - } - FileWrite(csocket, "\r\n", -1); - FileClose(&csocket); - Bye(EX_OK); - } - if (0 == strcmp((char *)acIn, "version")) { - FilePrint(csocket, "version `%s'\r\n", THIS_VERSION); - FileClose(&csocket); - Bye(EX_OK); - } - if (0 != strcmp((char *)acIn, "call")) { - FileWrite(csocket, "unknown command\r\n", -1); - FileClose(&csocket); - Bye(EX_OK); - } + /* init the fsm */ + pCL->iState = S_IDENT; + BuildString((char *)0, pCL->accmd); + BuildString((char *)0, pCL->peername); + BuildString((char *)0, pCL->username); + BuildString((char *)0, pCL->acid); - if ((char *)0 == pcArgs) { - FileWrite(csocket, "call requires argument\r\n", -1); - FileClose(&csocket); - Bye(EX_OK); - } + if (ClientAccessOk(pCL)) { + pCL->ioState = ISNORMAL; + /* say hi to start */ + FileWrite(pCL->fd, "ok\r\n", -1); + } else + DropMasterClient(pCL, FLAGFALSE); + } - /* look up the machine to call - */ - found = 0; - pRCFound = (REMOTE *) 0; - /* look for a local machine */ - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { - if (0 == pGE->imembers) - continue; - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - if (0 != strcasecmp(pcArgs, pCE->server.string)) { - continue; - } - prnum = ntohs(pGE->port); - ambiguous = BuildTmpString(pCE->server.string); - ambiguous = BuildTmpString(", "); - ++found; - } - } - /* Purposefully hunt for another match - this will detect - * duplicates - a bad state to be in. - * Does the readcfg.c code even check for dups? - */ - if (!fNoredir || (fNoredir && found == 0)) { - for (pRC = pRCList; (REMOTE *) 0 != pRC; pRC = pRC->pRCnext) { - if (0 != strcasecmp(pcArgs, pRC->rserver.string)) { - continue; - } - ambiguous = BuildTmpString(pRC->rserver.string); - ambiguous = BuildTmpString(", "); - ++found; - pRCFound = pRC; - } - } - if (found == 0) { /* Then look for substring matches */ - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { - if (0 == pGE->imembers) - continue; - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - if (0 != - strncasecmp(pcArgs, pCE->server.string, - strlen(pcArgs))) { - continue; - } - prnum = ntohs(pGE->port); - ambiguous = BuildTmpString(pCE->server.string); - ambiguous = BuildTmpString(", "); - ++found; - } - } - /* look for a remote server */ - /* again, looks for dups with local consoles */ - if (!fNoredir || (fNoredir && found != 1)) { - for (pRC = pRCList; (REMOTE *) 0 != pRC; - pRC = pRC->pRCnext) { - if (0 != - strncasecmp(pcArgs, pRC->rserver.string, - strlen(pcArgs))) { - continue; - } - ambiguous = BuildTmpString(pRC->rserver.string); - ambiguous = BuildTmpString(", "); - ++found; - pRCFound = pRC; - } - } - } - switch (found) { - case 0: - FilePrint(csocket, "console `%s' not found\r\n", pcArgs); - break; - case 1: - if ((REMOTE *) 0 != pRCFound) { - if (fNoredir) { - FilePrint(csocket, - "automatic redirection disabled - console on master `%s'\r\n", - pRCFound->rhost.string); - } else { - FilePrint(csocket, "@%s\r\n", - pRCFound->rhost.string); - } - } else { - FilePrint(csocket, "%hu\r\n", prnum); - } - break; - default: - found = strlen(ambiguous); - ambiguous[found - 2] = '\000'; - FilePrint(csocket, - "ambiguous console abbreviation, `%s'\r\n\tchoices are %s\r\n", - pcArgs, ambiguous); - break; - } - BuildTmpString((char *)0); /* we're done - clean up */ - ambiguous = (char *)0; - FileClose(&csocket); - Bye(EX_OK); + /* clean up the free list */ + while (pCLfree != (CONSCLIENT *)0) { + pCL = pCLfree->pCLnext; + DestroyClient(pCLfree); + pCLfree = pCL; } unlink(PIDFILE); diff --git a/conserver/readcfg.c b/conserver/readcfg.c index 5f61a0f..45ff829 100644 --- a/conserver/readcfg.c +++ b/conserver/readcfg.c @@ -1,116 +1,1368 @@ /* - * $Id: readcfg.c,v 5.104 2003-04-07 18:57:55-07 bryan Exp $ + * $Id: readcfg.c,v 5.137 2003-08-21 15:03:25-07 bryan Exp $ * * Copyright conserver.com, 2000 * * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) - * - * Copyright GNAC, Inc., 1998 */ /* - * Copyright (c) 1990 The Ohio State University. - * All rights reserved. + * Notes/Thoughts: + * + * - building access lists doesn't remove any dups in AccessDestroy(). + * it just joins lists that match the current host. it would be nice + * to have only unique items in the list. + * + * - the *Abort() stuff may not play well with the *Begin() stuff - if + * it's reusing the space, could we not have values trickle over into + * the next section? - i think i may have fixed that. + * + * - add the flow tag at some point + * + * s+ m max maximum consoles managed per process * - * Redistribution and use in source and binary forms are permitted - * provided that: (1) source distributions retain this entire copyright - * notice and comment, and (2) distributions including binaries display - * the following acknowledgement: ``This product includes software - * developed by The Ohio State University and its contributors'' - * in the documentation or other materials provided with the distribution - * and in all advertising materials mentioning features or use of this - * software. Neither the name of the University nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -/* - * Network console modifications by Robert Olson, olson@mcs.anl.gov. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include #include +#include #include #include #include -#include #include +/***** external things *****/ +NAMES *userList = (NAMES *)0; +GRPENT *pGroups = (GRPENT *)0; +REMOTE *pRCList = (REMOTE *)0; +ACCESS *pACList = (ACCESS *)0; +CONSENTUSERS *pADList = (CONSENTUSERS *)0; +REMOTE *pRCUniq = (REMOTE *)0; +CONFIG *pConfig = (CONFIG *)0; +BREAKS breakList[9] = { + {(STRING *)0, 0}, {(STRING *)0, 0}, {(STRING *)0, 0}, + {(STRING *)0, 0}, {(STRING *)0, 0}, {(STRING *)0, 0}, + {(STRING *)0, 0}, {(STRING *)0, 0}, {(STRING *)0, 0} +}; -GRPENT *pGroups = (GRPENT *) 0; -REMOTE *pRCList = (REMOTE *) 0; /* list of remote consoles we know about */ -ACCESS *pACList = (ACCESS *) 0; /* `who do you love' (or trust) */ -STRING *breakList = (STRING *) 0; /* list of break sequences */ -REMOTE *pRCUniq = (REMOTE *) 0; /* list of uniq console servers */ - -static unsigned int groupID = 0; - -/* Parse the [number(m|h|d|l)[a]] spec - * return 0 on invalid spec, non-zero on valid spec - */ -int +void #if PROTOTYPES -ParseMark(const char *pcFile, const int iLine, const char *pcMark, - time_t tyme, CONSENT * pCE) +DestroyBreakList(void) #else -ParseMark(pcFile, iLine, pcMark, tyme, pCE) - const char *pcFile; - const int iLine; - const char *pcMark; - time_t tyme; - CONSENT *pCE; +DestroyBreakList() #endif { - static STRING *mark = (STRING *) 0; - char *p, *n = (char *)0; - int activity = 0, bactivity = 0; + int i; + + for (i = 0; i < 9; i++) { + if (breakList[i].seq != (STRING *)0) { + DestroyString(breakList[i].seq); + breakList[i].seq = (STRING *)0; + } + } +} + +void +#if PROTOTYPES +DestroyUserList(void) +#else +DestroyUserList() +#endif +{ + NAMES *n; + while (userList != (NAMES *)0) { + n = userList->next; + if (userList->name != (char *)0) + free(userList->name); + free(userList); + userList = n; + } +} + +NAMES * +#if PROTOTYPES +FindUserList(char *id) +#else +FindUserList(id) + char *id; +#endif +{ + NAMES *u; + for (u = userList; u != (NAMES *)0; u = u->next) { + if (strcmp(u->name, id) == 0) + return u; + } + return u; +} + +NAMES * +#if PROTOTYPES +AddUserList(char *id) +#else +AddUserList(id) + char *id; +#endif +{ + NAMES *u; + + if ((u = FindUserList(id)) == (NAMES *)0) { + if ((u = (NAMES *)calloc(1, sizeof(NAMES))) + == (NAMES *)0) + OutOfMem(); + if ((u->name = strdup(id)) + == (char *)0) + OutOfMem(); + u->next = userList; + userList = u; + } + return u; +} + +/***** 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 BREAKDELAYDEFAULT 250 +#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; +GRPENT *pGE = (GRPENT *)0; +static unsigned int groupID = 0; +REMOTE **ppRC = (REMOTE **)0; + +/* 'break' handling */ +STRING *parserBreak = (STRING *)0; +int parserBreakDelay = 0; +int parserBreakNum = 0; + +CONSENTUSERS * +#if PROTOTYPES +ConsentAddUser(CONSENTUSERS **ppCU, char *id) +#else +ConsentAddUser(ppCU, id) + CONSENTUSERS **ppCU; + char *id; +#endif +{ + CONSENTUSERS *u = (CONSENTUSERS *)0; + + if ((u = ConsentFindUser(*ppCU, id)) == (CONSENTUSERS *)0) { + if ((u = (CONSENTUSERS *)calloc(1, sizeof(CONSENTUSERS))) + == (CONSENTUSERS *)0) + OutOfMem(); + u->user = AddUserList(id); + u->next = *ppCU; + *ppCU = u; + } + return u; +} + +void +#if PROTOTYPES +BreakBegin(char *id) +#else +BreakBegin(id) + char *id; +#endif +{ + CONDDEBUG((1, "BreakBegin(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000') || id[0] < '1' || id[0] > '9' + || id[1] != '\000') { + if (isMaster) + Error("invalid break number `%s' [%s:%d]", id, file, line); + parserBreakNum = 0; + } else { + parserBreakNum = id[0] - '0'; + if (parserBreak == (STRING *)0) + parserBreak = AllocString(); + else + BuildString((char *)0, parserBreak); + parserBreakDelay = BREAKDELAYDEFAULT; + } +} + +void +#if PROTOTYPES +BreakEnd(void) +#else +BreakEnd() +#endif +{ + CONDDEBUG((1, "BreakEnd() [%s:%d]", file, line)); + + if (parserBreakNum == 0) + return; + + BuildString((char *)0, breakList[parserBreakNum - 1].seq); + BuildString(parserBreak->string, breakList[parserBreakNum - 1].seq); + CleanupBreak(parserBreakNum); + breakList[parserBreakNum - 1].delay = parserBreakDelay; + parserBreakNum = 0; +} + +void +#if PROTOTYPES +BreakAbort(void) +#else +BreakAbort() +#endif +{ + CONDDEBUG((1, "BreakAbort() [%s:%d]", file, line)); + parserBreakNum = 0; +} + +void +#if PROTOTYPES +BreakDestroy(void) +#else +BreakDestroy() +#endif +{ + CONDDEBUG((1, "BreakDestroy() [%s:%d]", file, line)); + if (parserBreak != (STRING *)0) { + DestroyString(parserBreak); + parserBreak = (STRING *)0; + } +#if DUMPDATA + { + int i; + for (i = 0; i < 9; i++) { + Msg("Break[%d] = `%s', delay=%d", i, breakList[i].seq->string, + breakList[i].delay); + } + } +#endif +} + +void +#if PROTOTYPES +BreakItemString(char *id) +#else +BreakItemString(id) + char *id; +#endif +{ + CONDDEBUG((1, "BreakItemString(%s) [%s:%d]", id, file, line)); + BuildString((char *)0, parserBreak); + if ((id == (char *)0) || (*id == '\000')) + return; + BuildString(id, parserBreak); +} + +void +#if PROTOTYPES +BreakItemDelay(char *id) +#else +BreakItemDelay(id) + char *id; +#endif +{ + char *p; + int delay; + + CONDDEBUG((1, "BreakItemDelay(%s) [%s:%d]", id, file, line)); + + if ((id == (char *)0) || (*id == '\000')) { + parserBreakDelay = 0; + return; + } + + for (p = id; *p != '\000'; p++) + if (!isdigit((int)(*p))) + break; + /* if it wasn't a number or the number is out of bounds */ + if ((*p != '\000') || ((delay = atoi(id)) > 999)) { + if (isMaster) + Error("invalid port number `%s' [%s:%d]", id, file, line); + return; + } + parserBreakDelay = delay; +} + +/* 'group' handling */ +typedef struct parserGroupUsers { + NAMES *user; + struct parserGroupUsers *next; +} PARSERGROUPUSERS; + +typedef struct parserGroup { + STRING *name; + PARSERGROUPUSERS *users; + struct parserGroup *next; +} PARSERGROUP; + +PARSERGROUP *parserGroups = (PARSERGROUP *)0; +PARSERGROUP *parserGroupTemp = (PARSERGROUP *)0; + +void +#if PROTOTYPES +DestroyParserGroup(PARSERGROUP *pg) +#else +DestroyParserGroup(pg) + PARSERGROUP *pg; +#endif +{ + PARSERGROUP **ppg = &parserGroups; + PARSERGROUPUSERS *u = (PARSERGROUPUSERS *)0; + char *m = (char *)0; + + if (pg == (PARSERGROUP *)0) + return; + while (*ppg != (PARSERGROUP *)0) { + if (*ppg == pg) { + break; + } else { + ppg = &((*ppg)->next); + } + } + + BuildTmpString((char *)0); + m = BuildTmpString(pg->name->string); + if (*ppg != (PARSERGROUP *)0) + *ppg = pg->next; + DestroyString(pg->name); + for (u = pg->users; u != (PARSERGROUPUSERS *)0;) { + PARSERGROUPUSERS *n = u->next; + BuildTmpStringChar(','); + m = BuildTmpString(u->user->name); + free(u); + u = n; + } + free(pg); + CONDDEBUG((2, "DestroyParserGroup(): %s", m)); +} + +PARSERGROUP * +#if PROTOTYPES +GroupFind(char *id) +#else +GroupFind(id) + char *id; +#endif +{ + PARSERGROUP *pg; + for (pg = parserGroups; pg != (PARSERGROUP *)0; pg = pg->next) { + if (strcmp(id, pg->name->string) == 0) + return pg; + } + return pg; +} + +void +#if PROTOTYPES +GroupBegin(char *id) +#else +GroupBegin(id) + char *id; +#endif +{ + CONDDEBUG((1, "GroupBegin(%s) [%s:%d]", id, file, line)); + if (id == (char *)0 || id[0] == '\000') { + if (isMaster) + Error("empty group name [%s:%d]", file, line); + return; + } + if (parserGroupTemp != (PARSERGROUP *)0) + DestroyParserGroup(parserGroupTemp); + if ((parserGroupTemp = (PARSERGROUP *)calloc(1, sizeof(PARSERGROUP))) + == (PARSERGROUP *)0) + OutOfMem(); + parserGroupTemp->name = AllocString(); + BuildString(id, parserGroupTemp->name); +} + +void +#if PROTOTYPES +GroupEnd(void) +#else +GroupEnd() +#endif +{ + PARSERGROUP *pg = (PARSERGROUP *)0; + + CONDDEBUG((1, "GroupEnd() [%s:%d]", file, line)); + + if (parserGroupTemp->name->used <= 1) { + DestroyParserGroup(parserGroupTemp); + parserGroupTemp = (PARSERGROUP *)0; + return; + } + + /* if we're overriding an existing group, nuke it */ + if ((pg = + GroupFind(parserGroupTemp->name->string)) != (PARSERGROUP *)0) { + DestroyParserGroup(pg); + } + /* add the temp to the head of the list */ + parserGroupTemp->next = parserGroups; + parserGroups = parserGroupTemp; + parserGroupTemp = (PARSERGROUP *)0; +} + +void +#if PROTOTYPES +GroupAbort(void) +#else +GroupAbort() +#endif +{ + CONDDEBUG((1, "GroupAbort() [%s:%d]", file, line)); + DestroyParserGroup(parserGroupTemp); + parserGroupTemp = (PARSERGROUP *)0; +} + +void +#if PROTOTYPES +GroupDestroy(void) +#else +GroupDestroy() +#endif +{ + CONDDEBUG((1, "GroupDestroy() [%s:%d]", file, line)); +#if DUMPDATA + { + PARSERGROUP *pg; + NAMES *u; + for (pg = parserGroups; pg != (PARSERGROUP *)0; pg = pg->next) { + PARSERGROUPUSERS *pgu; + Msg("Group = %s", pg->name->string); + for (pgu = pg->users; pgu != (PARSERGROUPUSERS *)0; + pgu = pgu->next) { + Msg(" User = %s", pgu->user->name); + } + } + Msg("UserList..."); + for (u = userList; u != (NAMES *)0; u = u->next) { + Msg(" User = %s", u->name); + } + } +#endif + while (parserGroups != (PARSERGROUP *)0) + DestroyParserGroup(parserGroups); + DestroyParserGroup(parserGroupTemp); + parserGroups = parserGroupTemp = (PARSERGROUP *)0; +} + +PARSERGROUPUSERS * +#if PROTOTYPES +GroupFindUser(PARSERGROUP *pg, char *id) +#else +GroupFindUser(pg, id) + PARSERGROUP *pg; + char *id; +#endif +{ + PARSERGROUPUSERS *pgu; + for (pgu = pg->users; pgu != (PARSERGROUPUSERS *)0; pgu = pgu->next) { + if (strcmp(pgu->user->name, id) == 0) { + return pgu; + } + } + return pgu; +} + +PARSERGROUPUSERS * +#if PROTOTYPES +GroupAddUser(PARSERGROUP *pg, char *id) +#else +GroupAddUser(pg, id) + PARSERGROUP *pg; + char *id; +#endif +{ + PARSERGROUPUSERS *pgu = (PARSERGROUPUSERS *)0; + + if ((pgu = GroupFindUser(pg, id)) == (PARSERGROUPUSERS *)0) { + if ((pgu = (PARSERGROUPUSERS *)calloc(1, sizeof(PARSERGROUPUSERS))) + == (PARSERGROUPUSERS *)0) + OutOfMem(); + pgu->user = AddUserList(id); + pgu->next = pg->users; + pg->users = pgu; + } + return pgu; +} + +void +#if PROTOTYPES +GroupItemInclude(char *id) +#else +GroupItemInclude(id) + char *id; +#endif +{ + char *token = (char *)0; + PARSERGROUP *pg = (PARSERGROUP *)0; + + CONDDEBUG((1, "GroupItemInclude(%s) [%s:%d]", id, file, line)); + + if ((id == (char *)0) || (*id == '\000')) + return; + + for (token = strtok(id, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + if ((pg = GroupFind(token)) == (PARSERGROUP *)0) { + if (isMaster) + Error("unknown group name `%s' [%s:%d]", token, file, + line); + } else { + PARSERGROUPUSERS *pgu; + for (pgu = pg->users; pgu != (PARSERGROUPUSERS *)0; + pgu = pgu->next) { + GroupAddUser(parserGroupTemp, pgu->user->name); + } + } + } +} + +void +#if PROTOTYPES +GroupItemUsers(char *id) +#else +GroupItemUsers(id) + char *id; +#endif +{ + char *token = (char *)0; + PARSERGROUP *pg = (PARSERGROUP *)0; + + CONDDEBUG((1, "GroupItemUsers(%s) [%s:%d]", id, file, line)); + + if ((id == (char *)0) || (*id == '\000')) { + PARSERGROUPUSERS *u; + for (u = parserGroupTemp->users; u != (PARSERGROUPUSERS *)0;) { + PARSERGROUPUSERS *n = u->next; + free(u); + u = n; + } + return; + } + + for (token = strtok(id, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + if ((pg = GroupFind(token)) == (PARSERGROUP *)0) { + GroupAddUser(parserGroupTemp, token); + } else { + PARSERGROUPUSERS *pgu; + for (pgu = pg->users; pgu != (PARSERGROUPUSERS *)0; + pgu = pgu->next) { + GroupAddUser(parserGroupTemp, pgu->user->name); + } + } + } +} + +/* 'default' handling */ +CONSENT *parserDefaults = (CONSENT *)0; +CONSENT **parserDefaultsTail = &parserDefaults; +CONSENT *parserDefaultTemp = (CONSENT *)0; + +void +#if PROTOTYPES +DestroyParserDefaultOrConsole(CONSENT *c, CONSENT **ph, CONSENT ***pt) +#else +DestroyParserDefaultOrConsole(c, ph, pt) + CONSENT *c; + CONSENT **ph; + CONSENT ***pt; +#endif +{ + if (c == (CONSENT *)0) + return; + + CONDDEBUG((2, "DestroyParserDefaultOrConsole(): %s", c->server)); + + if (ph != (CONSENT **)0) { + while (*ph != (CONSENT *)0) { + if (*ph == c) { + break; + } else { + ph = &((*ph)->pCEnext); + } + } + + /* if we were in a chain... */ + if (*ph != (CONSENT *)0) { + /* unlink from the chain */ + *ph = c->pCEnext; + /* and possibly fix tail ptr... */ + if (c->pCEnext == (CONSENT *)0) + (*pt) = ph; + } + } + + DestroyConsentUsers(&(c->ro)); + DestroyConsentUsers(&(c->rw)); + + if (c->server != (char *)0) + free(c->server); + if (c->host != (char *)0) + free(c->host); + if (c->master != (char *)0) + free(c->master); + if (c->exec != (char *)0) + free(c->exec); + if (c->device != (char *)0) + free(c->device); + if (c->logfile != (char *)0) + free(c->logfile); + if (c->execSlave != (char *)0) + free(c->execSlave); + if (c->wbuf != (STRING *)0) + DestroyString(c->wbuf); + free(c); +} + +CONSENT * +#if PROTOTYPES +FindParserDefaultOrConsole(CONSENT *c, char *id) +#else +FindParserDefaultOrConsole(c, id) + CONSENT *c; + char *id; +#endif +{ + for (; c != (CONSENT *)0; c = c->pCEnext) { + if (strcasecmp(id, c->server) == 0) + return c; + } + return c; +} + +void +#if PROTOTYPES +ApplyDefault(CONSENT *d, CONSENT *c) +#else +ApplyDefault(d, c) + CONSENT *d; + CONSENT *c; +#endif +{ + if (d->type != UNKNOWN) + c->type = d->type; + if (d->breakNum != 0) + c->breakNum = d->breakNum; + if (d->baud != (BAUD *)0) + c->baud = d->baud; + if (d->parity != (PARITY *)0) + c->parity = d->parity; + if (d->port != 0) + c->port = d->port; + if (d->mark != 0) + c->mark = d->mark; + if (d->nextMark != 0) + c->nextMark = d->nextMark; + if (d->activitylog != FLAGUNKNOWN) + c->activitylog = d->activitylog; + if (d->breaklog != FLAGUNKNOWN) + c->breaklog = d->breaklog; + if (d->hupcl != FLAGUNKNOWN) + c->hupcl = d->hupcl; + if (d->cstopb != FLAGUNKNOWN) + c->cstopb = d->cstopb; + if (d->ixany != FLAGUNKNOWN) + c->ixany = d->ixany; + if (d->ixon != FLAGUNKNOWN) + c->ixon = d->ixon; + if (d->ixoff != FLAGUNKNOWN) + c->ixoff = d->ixoff; +#if defined(CRTSCTS) + if (d->crtscts != FLAGUNKNOWN) + c->crtscts = d->crtscts; +#endif + if (d->ondemand != FLAGUNKNOWN) + c->ondemand = d->ondemand; + if (d->striphigh != FLAGUNKNOWN) + c->striphigh = d->striphigh; + if (d->reinitoncc != FLAGUNKNOWN) + c->reinitoncc = d->reinitoncc; + if (d->autoreinit != FLAGUNKNOWN) + c->autoreinit = d->autoreinit; + if (d->unloved != FLAGUNKNOWN) + c->unloved = d->unloved; + if (d->host != (char *)0) { + if (c->host != (char *)0) + free(c->host); + if ((c->host = strdup(d->host)) == (char *)0) + OutOfMem(); + } + if (d->master != (char *)0) { + if (c->master != (char *)0) + free(c->master); + if ((c->master = strdup(d->master)) == (char *)0) + OutOfMem(); + } + if (d->exec != (char *)0) { + if (c->exec != (char *)0) + free(c->exec); + if ((c->exec = strdup(d->exec)) == (char *)0) + OutOfMem(); + } + if (d->device != (char *)0) { + if (c->device != (char *)0) + free(c->device); + if ((c->device = strdup(d->device)) == (char *)0) + OutOfMem(); + } + if (d->logfile != (char *)0) { + if (c->logfile != (char *)0) + free(c->logfile); + if ((c->logfile = strdup(d->logfile)) == (char *)0) + OutOfMem(); + } + if (d->ro != (CONSENTUSERS *)0) { + CONSENTUSERS *u; + for (u = d->ro; u != (CONSENTUSERS *)0; u = u->next) { + ConsentAddUser(&(c->ro), u->user->name); + } + } + if (d->rw != (CONSENTUSERS *)0) { + CONSENTUSERS *u; + for (u = d->rw; u != (CONSENTUSERS *)0; u = u->next) { + ConsentAddUser(&(c->rw), u->user->name); + } + } +} + +void +#if PROTOTYPES +DefaultBegin(char *id) +#else +DefaultBegin(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultBegin(%s) [%s: %d]", id, file, line)); + if (id == (char *)0 || id[0] == '\000') { + if (isMaster) + Error("empty default name [%s:%d]", file, line); + return; + } + if (parserDefaultTemp != (CONSENT *)0) + DestroyParserDefaultOrConsole(parserDefaultTemp, (CONSENT **)0, + (CONSENT ***)0); + if ((parserDefaultTemp = (CONSENT *)calloc(1, sizeof(CONSENT))) + == (CONSENT *)0) + OutOfMem(); + + if ((parserDefaultTemp->server = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +DefaultEnd(void) +#else +DefaultEnd() +#endif +{ + CONSENT *c = (CONSENT *)0; + + CONDDEBUG((1, "DefaultEnd() [%s:%d]", file, line)); + + if (parserDefaultTemp->server == (char *)0) { + DestroyParserDefaultOrConsole(parserDefaultTemp, (CONSENT **)0, + (CONSENT ***)0); + parserDefaultTemp = (CONSENT *)0; + return; + } + + /* if we're overriding an existing default, nuke it */ + if ((c = + FindParserDefaultOrConsole(parserDefaults, + parserDefaultTemp->server)) != + (CONSENT *)0) { + DestroyParserDefaultOrConsole(c, &parserDefaults, + &parserDefaultsTail); + } + + /* add the temp to the tail of the list */ + *parserDefaultsTail = parserDefaultTemp; + parserDefaultsTail = &(parserDefaultTemp->pCEnext); + parserDefaultTemp = (CONSENT *)0; +} + +void +#if PROTOTYPES +DefaultAbort(void) +#else +DefaultAbort() +#endif +{ + CONDDEBUG((1, "DefaultAbort() [%s:%d]", file, line)); + DestroyParserDefaultOrConsole(parserDefaultTemp, (CONSENT **)0, + (CONSENT ***)0); + parserDefaultTemp = (CONSENT *)0; +} + +void +#if PROTOTYPES +DefaultDestroy(void) +#else +DefaultDestroy() +#endif +{ + CONDDEBUG((1, "DefaultDestroy() [%s:%d]", file, line)); + + while (parserDefaults != (CONSENT *)0) + DestroyParserDefaultOrConsole(parserDefaults, &parserDefaults, + &parserDefaultsTail); + DestroyParserDefaultOrConsole(parserDefaultTemp, (CONSENT **)0, + (CONSENT ***)0); + parserDefaults = parserDefaultTemp = (CONSENT *)0; +} + +void +#if PROTOTYPES +ProcessBaud(CONSENT *c, char *id) +#else +ProcessBaud(c, id) + CONSENT *c; + char *id; +#endif +{ + if ((id == (char *)0) || (*id == '\000')) { + c->baud = (BAUD *)0; + return; + } + c->baud = FindBaud(id); + if (c->baud == (BAUD *)0) { + if (isMaster) + Error("invalid baud rate `%s' [%s:%d]", id, file, line); + } +} + +void +#if PROTOTYPES +DefaultItemBaud(char *id) +#else +DefaultItemBaud(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemBaud(%s) [%s:%d]", id, file, line)); + ProcessBaud(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessBreak(CONSENT *c, char *id) +#else +ProcessBreak(c, id) + CONSENT *c; + char *id; +#endif +{ + if ((id == (char *)0) || (*id == '\000')) { + c->breakNum = 0; + return; + } + if ((id[0] >= '1') && (id[0] <= '9') && (id[1] == '\000')) { + c->breakNum = id[0] - '0'; + return; + } + if (isMaster) + Error("invalid break number `%s' [%s:%d]", id, file, line); +} + +void +#if PROTOTYPES +DefaultItemBreak(char *id) +#else +DefaultItemBreak(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemBreak(%s) [%s:%d]", id, file, line)); + ProcessBreak(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessDevice(CONSENT *c, char *id) +#else +ProcessDevice(c, id) + CONSENT *c; + char *id; +#endif +{ + if (c->device != (char *)0) { + free(c->device); + c->device = (char *)0; + } + if ((id == (char *)0) || (*id == '\000')) + return; + if ((c->device = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +DefaultItemDevice(char *id) +#else +DefaultItemDevice(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemDevice(%s) [%s:%d]", id, file, line)); + ProcessDevice(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessExec(CONSENT *c, char *id) +#else +ProcessExec(c, id) + CONSENT *c; + char *id; +#endif +{ + if (c->exec != (char *)0) { + free(c->exec); + c->exec = (char *)0; + } + if (id == (char *)0 || id[0] == '\000') { + return; + } + if ((c->exec = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +DefaultItemExec(char *id) +#else +DefaultItemExec(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemExec(%s) [%s:%d]", id, file, line)); + ProcessExec(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessFlow(CONSENT *c, char *id) +#else +ProcessFlow(c, id) + CONSENT *c; + char *id; +#endif +{ + if (isMaster) + Error("unimplemented code for `flow' [%s:%d]", file, line); +} + +void +#if PROTOTYPES +DefaultItemFlow(char *id) +#else +DefaultItemFlow(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemFlow(%s) [%s:%d]", id, file, line)); + ProcessFlow(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessHost(CONSENT *c, char *id) +#else +ProcessHost(c, id) + CONSENT *c; + char *id; +#endif +{ + if (c->host != (char *)0) { + free(c->host); + c->host = (char *)0; + } + if ((id == (char *)0) || (*id == '\000')) + return; + if ((c->host = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +DefaultItemHost(char *id) +#else +DefaultItemHost(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemHost(%s) [%s:%d]", id, file, line)); + ProcessHost(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessInclude(CONSENT *c, char *id) +#else +ProcessInclude(c, id) + CONSENT *c; + char *id; +#endif +{ + CONSENT *inc = (CONSENT *)0; + if ((id == (char *)0) || (*id == '\000')) + return; + if ((inc = + FindParserDefaultOrConsole(parserDefaults, id)) != (CONSENT *)0) { + ApplyDefault(inc, c); + } else { + if (isMaster) + Error("invalid default name `%s' [%s:%d]", id, file, line); + } +} + +void +#if PROTOTYPES +DefaultItemInclude(char *id) +#else +DefaultItemInclude(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemInclude(%s) [%s:%d]", id, file, line)); + ProcessInclude(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessLogfile(CONSENT *c, char *id) +#else +ProcessLogfile(c, id) + CONSENT *c; + char *id; +#endif +{ + if (c->logfile != (char *)0) { + free(c->logfile); + c->logfile = (char *)0; + } + if (id == (char *)0 || id[0] == '\000') { + return; + } + if ((c->logfile = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +DefaultItemLogfile(char *id) +#else +DefaultItemLogfile(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemLogfile(%s) [%s:%d]", id, file, line)); + ProcessLogfile(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessMaster(CONSENT *c, char *id) +#else +ProcessMaster(c, id) + CONSENT *c; + char *id; +#endif +{ + if (c->master != (char *)0) { + free(c->master); + c->master = (char *)0; + } + if ((id == (char *)0) || (*id == '\000')) + return; + if ((c->master = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +DefaultItemMaster(char *id) +#else +DefaultItemMaster(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemMaster(%s) [%s:%d]", id, file, line)); + ProcessMaster(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessOptions(CONSENT *c, char *id) +#else +ProcessOptions(c, id) + CONSENT *c; + char *id; +#endif +{ + char *token = (char *)0; + int negative = 0; + + if ((id == (char *)0) || (*id == '\000')) { + c->hupcl = FLAGUNKNOWN; + c->cstopb = FLAGUNKNOWN; + c->ixany = FLAGUNKNOWN; + c->ixon = FLAGUNKNOWN; + c->ixoff = FLAGUNKNOWN; +#if defined(CRTSCTS) + c->crtscts = FLAGUNKNOWN; +#endif + c->ondemand = FLAGUNKNOWN; + c->striphigh = FLAGUNKNOWN; + c->reinitoncc = FLAGUNKNOWN; + c->autoreinit = FLAGUNKNOWN; + c->unloved = FLAGUNKNOWN; + return; + } + + for (token = strtok(id, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + if (token[0] == '!') { + negative = 1; + token++; + } else { + negative = 0; + } + if (strcasecmp("hupcl", token) == 0) + c->hupcl = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("ixany", token) == 0) + c->ixany = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("ixon", token) == 0) + c->ixon = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("ixoff", token) == 0) + c->ixoff = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("cstopb", token) == 0) + c->cstopb = negative ? FLAGFALSE : FLAGTRUE; +#if defined(CRTSCTS) + else if (strcasecmp("crtscts", token) == 0) + c->crtscts = negative ? FLAGFALSE : FLAGTRUE; +#endif + else if (strcasecmp("ondemand", token) == 0) + c->ondemand = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("striphigh", token) == 0) + c->striphigh = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("reinitoncc", token) == 0) + c->reinitoncc = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("autoreinit", token) == 0) + c->autoreinit = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("unloved", token) == 0) + c->unloved = negative ? FLAGFALSE : FLAGTRUE; + else + Error("invalid option `%s' [%s:%d]", token, file, line); + } +} + +void +#if PROTOTYPES +DefaultItemOptions(char *id) +#else +DefaultItemOptions(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemOptions(%s) [%s:%d]", id, file, line)); + ProcessOptions(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessParity(CONSENT *c, char *id) +#else +ProcessParity(c, id) + CONSENT *c; + char *id; +#endif +{ + if ((id == (char *)0) || (*id == '\000')) { + c->parity = (PARITY *)0; + return; + } + c->parity = FindParity(id); + if (c->parity == (PARITY *)0) { + if (isMaster) + Error("invalid parity type `%s' [%s:%d]", id, file, line); + } +} + +void +#if PROTOTYPES +DefaultItemParity(char *id) +#else +DefaultItemParity(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemParity(%s) [%s:%d]", id, file, line)); + ProcessParity(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessPort(CONSENT *c, char *id) +#else +ProcessPort(c, id) + CONSENT *c; + char *id; +#endif +{ + char *p; + + if ((id == (char *)0) || (*id == '\000')) { + c->port = 0; + return; + } + for (p = id; *p != '\000'; p++) + if (!isdigit((int)(*p))) + break; + /* if it wasn't a number or the number was zero */ + if ((*p != '\000') || ((c->port = (unsigned short)atoi(id)) == 0)) { + if (isMaster) + Error("invalid port number `%s' [%s:%d]", id, file, line); + return; + } +} + +void +#if PROTOTYPES +DefaultItemPort(char *id) +#else +DefaultItemPort(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemPort(%s) [%s:%d]", id, file, line)); + ProcessPort(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessRoRw(CONSENTUSERS **ppCU, char *id) +#else +ProcessRoRw(ppCU, id) + CONSENTUSERS **ppCU; + char *id; +#endif +{ + char *token = (char *)0; + PARSERGROUP *pg = (PARSERGROUP *)0; + + CONDDEBUG((1, "ProcessRoRw(%s) [%s:%d]", id, file, line)); + + if ((id == (char *)0) || (*id == '\000')) { + DestroyConsentUsers(ppCU); + return; + } + + for (token = strtok(id, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + if ((pg = GroupFind(token)) == (PARSERGROUP *)0) { + ConsentAddUser(ppCU, token); + } else { + PARSERGROUPUSERS *pgu; + for (pgu = pg->users; pgu != (PARSERGROUPUSERS *)0; + pgu = pgu->next) { + ConsentAddUser(ppCU, pgu->user->name); + } + } + } +} + +void +#if PROTOTYPES +DefaultItemRo(char *id) +#else +DefaultItemRo(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemRo(%s) [%s:%d]", id, file, line)); + ProcessRoRw(&(parserDefaultTemp->ro), id); +} + +void +#if PROTOTYPES +DefaultItemRw(char *id) +#else +DefaultItemRw(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemRw(%s) [%s:%d]", id, file, line)); + ProcessRoRw(&(parserDefaultTemp->rw), id); +} + +void +#if PROTOTYPES +ProcessTimestamp(CONSENT *c, char *id) +#else +ProcessTimestamp(c, id) + CONSENT *c; + char *id; +#endif +{ + time_t tyme; + char *p = (char *)0, *n = (char *)0; + FLAG activity = FLAGFALSE, bactivity = FLAGFALSE; int factor = 0, pfactor = 0; int value = 0, pvalue = 0; - if ((pcMark == (char *)0) || (*pcMark == '\000')) - return 0; + if ((id == (char *)0) || (*id == '\000')) { + c->breaklog = FLAGFALSE; + c->activitylog = FLAGFALSE; + c->nextMark = 0; + c->mark = 0; + return; + } - if (mark == (STRING *) 0) - mark = AllocString(); + /* Parse the [number(m|h|d|l)[a][b]] spec */ + tyme = time((time_t *)0); - BuildString((char *)0, mark); - BuildString(pcMark, mark); - - for (p = mark->string; *p != '\000'; p++) { + for (p = id; *p != '\000'; p++) { if (*p == 'a' || *p == 'A') { if (n != (char *)0) { - Error - ("%s(%d) bad timestamp specification `%s': numeral before `a' (ignoring numeral)", - pcFile, iLine, pcMark); + if (isMaster) + Error + ("invalid timestamp specification `%s': numeral before `a' (ignoring numeral) [%s:%d]", + id, file, line); } - activity = 1; + activity = FLAGTRUE; } else if (*p == 'b' || *p == 'B') { if (n != (char *)0) { - Error - ("%s(%d) bad timestamp specification `%s': numeral before `b' (ignoring numeral)", - pcFile, iLine, pcMark); + if (isMaster) + Error + ("invalid timestamp specification `%s': numeral before `b' (ignoring numeral) [%s:%d]", + id, file, line); } - bactivity = 1; + bactivity = FLAGTRUE; } else if (*p == 'm' || *p == 'M') { pfactor = 60; } else if (*p == 'h' || *p == 'H') { @@ -127,24 +1379,28 @@ ParseMark(pcFile, iLine, pcMark, tyme, pCE) pfactor = 60; } } else { - Error - ("%s(%d) bad timestamp specification `%s': unknown character `%c'", - pcFile, iLine, pcMark, *p); - return 0; + if (isMaster) + Error + ("invalid timestamp specification `%s': unknown character `%c' [%s:%d]", + id, *p, file, line); + return; } if (pfactor) { if (n == (char *)0) { - Error - ("%s(%d) bad timestamp specification `%s': missing numeric prefix for `%c'", - pcFile, iLine, pcMark, *p); - return 0; + if (isMaster) + Error + ("invalid timestamp specification `%s': missing numeric prefix for `%c' [%s:%d]", + id, *p, file, line); + return; } else { *p = '\000'; pvalue = atoi(n); if (pvalue < 0) { - Error("%s(%d) negative timestamp specification `%s'", - pcFile, iLine, pcMark); - return 0; + if (isMaster) + Error + ("negative timestamp specification `%s' [%s:%d]", + id, file, line); + return; } n = (char *)0; factor = pfactor; @@ -157,810 +1413,796 @@ ParseMark(pcFile, iLine, pcMark, tyme, pCE) if (n != (char *)0) { pvalue = atoi(n); if (pvalue < 0) { - Error("%s(%d) negative timestamp specification `%s'", pcFile, - iLine, pcMark); - return 0; + if (isMaster) + Error("negative timestamp specification `%s' [%s:%d]", id, + file, line); + return; } factor = 60; value = pvalue * factor; } - Debug(1, - "ParseMark(): mark spec of `%s' parsed: factor=%d, value=%d, activity=%d, bactivity=%d", - pcMark, factor, value, activity, bactivity); + CONDDEBUG((1, + "ProcessTimestamp(): mark spec of `%s' parsed: factor=%d, value=%d, activity=%d, bactivity=%d", + id, factor, value, activity, bactivity)); - if (pCE != (CONSENT *) 0) { - pCE->activitylog = activity; - pCE->breaklog = bactivity; - if (factor && value) { - pCE->mark = value; - if (factor > 0) { - tyme -= (tyme % 60); /* minute boundary */ - if ((value <= 60 * 60 && (60 * 60) % value == 0) - || (value > 60 * 60 && (60 * 60 * 24) % value == 0)) { - struct tm *tm; - time_t now; + c->activitylog = activity; + c->breaklog = bactivity; + if (factor && value) { + c->mark = value; + if (factor > 0) { + tyme -= (tyme % 60); /* minute boundary */ + if ((value <= 60 * 60 && (60 * 60) % value == 0) + || (value > 60 * 60 && (60 * 60 * 24) % value == 0)) { + struct tm *tm; + time_t now; - /* the increment is a "nice" subdivision of an hour - * or a day - */ - now = tyme; - if ((struct tm *)0 != (tm = localtime(&tyme))) { - tyme -= tm->tm_min * 60; /* hour boundary */ - tyme -= tm->tm_hour * 60 * 60; /* day boundary */ - tyme += ((now - tyme) / value) * value; - /* up to nice bound */ - } + /* the increment is a "nice" subdivision of an hour + * or a day + */ + now = tyme; + if ((struct tm *)0 != (tm = localtime(&tyme))) { + tyme -= tm->tm_min * 60; /* hour boundary */ + tyme -= tm->tm_hour * 60 * 60; /* day boundary */ + tyme += ((now - tyme) / value) * value; + /* up to nice bound */ } - pCE->nextMark = tyme + value; /* next boundary */ - } else { - pCE->nextMark = value; } + c->nextMark = tyme + value; /* next boundary */ } else { - pCE->nextMark = pCE->mark = 0; - } - } - - return factor; -} - -/* replace trailing space with '\000' in a string and return - * a pointer to the start of the non-space part - */ -char * -#if PROTOTYPES -PruneSpace(char *string) -#else -PruneSpace(string) - char *string; -#endif -{ - char *p; - char *head = (char *)0; - char *tail = (char *)0; - - /* Don't do much if it's crap */ - if (string == (char *)0 || *string == '\000') - return string; - - /* Now for the tricky part - search the string */ - for (p = string; *p != '\000'; p++) { - if (isspace((int)(*p))) { - if (tail == (char *)0) - tail = p; /* possible end of string */ - } else { - if (head == (char *)0) - head = p; /* found the start */ - tail = (char *)0; /* reset tail */ - } - } - - if (tail != (char *)0) - *tail = '\000'; - - if (head != (char *)0) - return head; - else - return string; -} - -void -#if PROTOTYPES -DestroyBreakList(void) -#else -DestroyBreakList() -#endif -{ - int i; - - if (breakList == (STRING *) 0) - return; - - for (i = 0; i < 9; i++) { - DestroyString(&breakList[i]); - } - free(breakList); - breakList = (STRING *) 0; -} - -/* read in the configuration file, fill in all the structs we use (ksb) - * to manage the consoles - */ -void -#if PROTOTYPES -ReadCfg(char *pcFile, FILE * fp) -#else -ReadCfg(pcFile, fp, master) - char *pcFile; - FILE *fp; -#endif -{ - ACCESS *pACtmp; - ACCESS **ppAC; - GRPENT **ppGE; - GRPENT *pGE = (GRPENT *) 0; - GRPENT *pGEtmp = (GRPENT *) 0; - GRPENT *pGEmatch = (GRPENT *) 0; - GRPENT *pGEstage = (GRPENT *) 0; - int iLine; - unsigned char *acIn; - static STRING *acInSave = (STRING *) 0; - char *acStart; - CONSENT *pCE = (CONSENT *) 0; - CONSENT *pCEtmp = (CONSENT *) 0; - CONSENT *pCEmatch = (CONSENT *) 0; - REMOTE **ppRC; - REMOTE *pRCtmp; - static STRING *logDirectory = (STRING *) 0; - time_t tyme; - static STRING *defMark = (STRING *) 0; - int isStartup = (pGroups == (GRPENT *) 0 && pRCList == (REMOTE *) 0); - REMOTE *pRCListOld = (REMOTE *) 0; - GRPENT *pGroupsOld = (GRPENT *) 0; - CONSCLIENT *pCLtmp = (CONSCLIENT *) 0; -#if HAVE_DMALLOC && DMALLOC_MARK_READCFG - unsigned long dmallocMarkReadCfg = 0; -#endif - - /* if we're the master process, this will either be the first time - * reading the config file (in which case we'll just build the two - * data structures: local and remote consoles), or it will be the - * Nth time through, and we'll adjust the existing data structures - * so that everything looks straight (using the same adjustment - * logic as the children so everyone is in sync). now, by adjusting - * i actually mean that we move aside all the old groups and start - * moving them back into the active list as we come across them in - * the config file. anything we haven't moved back into the active - * list then gets nuked. - * - * if we're the children, this is a reread of the config file (by - * definition). in that case, we just need to remove any consoles - * that have left our control or adjust the attributes of any consoles - * we get to keep. - * - * yep, slippery little slope we're walking here. hope we survive! - */ -#if HAVE_DMALLOC && DMALLOC_MARK_READCFG - dmallocMarkReadCfg = dmalloc_mark(); -#endif - if (acInSave == (STRING *) 0) - acInSave = AllocString(); - if (logDirectory == (STRING *) 0) - logDirectory = AllocString(); - if (defMark == (STRING *) 0) - defMark = AllocString(); - - if (!isStartup) { - pGroupsOld = pGroups; - pRCListOld = pRCList; - pGroups = (GRPENT *) 0; - pRCList = (REMOTE *) 0; - } - - tyme = time((time_t *) 0); - BuildString((char *)0, defMark); - BuildString((char *)0, logDirectory); - BuildString((char *)0, acInSave); - ppRC = &pRCList; - - /* initialize the break lists */ - if ((STRING *) 0 == breakList) { - breakList = (STRING *) calloc(9, sizeof(STRING)); - if ((STRING *) 0 == breakList) { - OutOfMem(); + c->nextMark = value; } } else { - for (iLine = 0; iLine < 9; iLine++) { - BuildString((char *)0, &breakList[iLine]); + c->nextMark = c->mark = 0; + } +} + +void +#if PROTOTYPES +DefaultItemTimestamp(char *id) +#else +DefaultItemTimestamp(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemTimestamp(%s) [%s:%d]", id, file, line)); + ProcessTimestamp(parserDefaultTemp, id); +} + +void +#if PROTOTYPES +ProcessType(CONSENT *c, char *id) +#else +ProcessType(c, id) + CONSENT *c; + char *id; +#endif +{ + CONSTYPE t = UNKNOWN; + if ((id == (char *)0) || (*id == '\000')) { + c->type = t; + return; + } + if (strcasecmp("device", id) == 0) + t = DEVICE; + else if (strcasecmp("exec", id) == 0) + t = EXEC; + else if (strcasecmp("host", id) == 0) + t = HOST; + if (t == UNKNOWN) { + if (isMaster) + Error("invalid console type `%s' [%s:%d]", id, file, line); + } else + c->type = t; +} + +void +#if PROTOTYPES +DefaultItemType(char *id) +#else +DefaultItemType(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemType(%s) [%s:%d]", id, file, line)); + ProcessType(parserDefaultTemp, id); +} + +/* 'console' handling */ +CONSENT *parserConsoles = (CONSENT *)0; +CONSENT **parserConsolesTail = &parserConsoles; +CONSENT *parserConsoleTemp = (CONSENT *)0; + +void +#if PROTOTYPES +ConsoleBegin(char *id) +#else +ConsoleBegin(id) + char *id; +#endif +{ + CONSENT *c; + + CONDDEBUG((1, "ConsoleBegin(%s) [%s:%d]", id, file, line)); + if (id == (char *)0 || id[0] == '\000') { + if (isMaster) + Error("empty console name [%s:%d]", file, line); + return; + } + if (parserConsoleTemp != (CONSENT *)0) + DestroyParserDefaultOrConsole(parserConsoleTemp, (CONSENT **)0, + (CONSENT ***)0); + if ((parserConsoleTemp = (CONSENT *)calloc(1, sizeof(CONSENT))) + == (CONSENT *)0) + OutOfMem(); + + /* prime the pump with a default of "*" */ + if ((c = + FindParserDefaultOrConsole(parserDefaults, + "*")) != (CONSENT *)0) { + ApplyDefault(c, parserConsoleTemp); + } + if ((parserConsoleTemp->server = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConsoleEnd(void) +#else +ConsoleEnd() +#endif +{ + int invalid = 0; + + CONSENT *c = (CONSENT *)0; + + CONDDEBUG((1, "ConsoleEnd() [%s:%d]", file, line)); + + if (parserConsoleTemp->master == (char *)0) { + if (isMaster) + Error("[%s] console missing 'master' attribute [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + } + + switch (parserConsoleTemp->type) { + case EXEC: + break; + case DEVICE: + if (parserConsoleTemp->device == (char *)0) { + if (isMaster) + Error + ("[%s] console missing 'device' attribute [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + } + if (parserConsoleTemp->baud == (BAUD *)0) { + if (isMaster) + Error("[%s] console missing 'baud' attribute [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + } + if (parserConsoleTemp->parity == (PARITY *)0) { + if (isMaster) + Error + ("[%s] console missing 'parity' attribute [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + } + break; + case HOST: + if (parserConsoleTemp->host == (char *)0) { + if (isMaster) + Error("[%s] console missing 'host' attribute [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + } + if (parserConsoleTemp->port == 0) { + if (isMaster) + Error("[%s] console missing 'port' attribute [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + } + break; + case UNKNOWN: + if (isMaster) + Error("[%s] console type unknown [%s:%d]", + parserConsoleTemp->server, file, line); + invalid = 1; + break; + } + + if (invalid != 0) { + DestroyParserDefaultOrConsole(parserConsoleTemp, (CONSENT **)0, + (CONSENT ***)0); + parserConsoleTemp = (CONSENT *)0; + return; + } + + /* if we're overriding an existing console, nuke it */ + if ((c = + FindParserDefaultOrConsole(parserConsoles, + parserConsoleTemp->server)) != + (CONSENT *)0) { + if (isMaster) + Error("console definition for `%s' overridden [%s:%d]", + parserConsoleTemp->server, file, line); + DestroyParserDefaultOrConsole(c, &parserConsoles, + &parserConsolesTail); + } + + /* add the temp to the tail of the list */ + *parserConsolesTail = parserConsoleTemp; + parserConsolesTail = &(parserConsoleTemp->pCEnext); + parserConsoleTemp = (CONSENT *)0; +} + +void +#if PROTOTYPES +ConsoleAbort(void) +#else +ConsoleAbort() +#endif +{ + CONDDEBUG((1, "ConsoleAbort() [%s:%d]", file, line)); + DestroyParserDefaultOrConsole(parserConsoleTemp, (CONSENT **)0, + (CONSENT ***)0); + parserConsoleTemp = (CONSENT *)0; +} + +void +#if PROTOTYPES +SwapStr(char *s1, char *s2) +#else +SwapStr(s1, s2) + char *s1; + char *s2; +#endif +{ + char *s; + s = s1; + s1 = s2; + s2 = s; +} + +void +#if PROTOTYPES +ExpandLogfile(CONSENT *c, char *id) +#else +ExpandLogfile(c, id) + CONSENT *c; + char *id; +#endif +{ + char *amp = (char *)0; + char *p = (char *)0; + char *tmp = (char *)0; + + if (id == (char *)0) + return; + /* + * Here we substitute the console name for any '&' character in the + * logfile name. That way you can just have something like + * "/var/console/&" for each of the conserver.cf entries. + */ + p = id; + BuildTmpString((char *)0); + while ((amp = strchr(p, '&')) != (char *)0) { + *amp = '\000'; + BuildTmpString(p); + BuildTmpString(c->server); + p = amp + 1; + *amp = '&'; + } + tmp = BuildTmpString(p); + if ((c->logfile = strdup(tmp)) + == (char *)0) + OutOfMem(); +} + +/* this will adjust parserConsoles/parserConsolesTail if we're adding + * a new console. + */ +void +#if PROTOTYPES +ConsoleAdd(CONSENT *c) +#else +ConsoleAdd(c) + CONSENT *c; +#endif +{ + CONSENT *pCEmatch = (CONSENT *)0; + GRPENT *pGEmatch = (GRPENT *)0, *pGEtmp = (GRPENT *)0; + CONSCLIENT *pCLtmp = (CONSCLIENT *)0; + CONSENTUSERS *u; + + /* check for remote consoles */ + if (!IsMe(c->master)) { + if (isMaster) { + REMOTE *pRCTemp; + if ((pRCTemp = (REMOTE *)calloc(1, sizeof(REMOTE))) + == (REMOTE *)0) + OutOfMem(); + if ((pRCTemp->rhost = strdup(c->master)) + == (char *)0) + OutOfMem(); + if ((pRCTemp->rserver = strdup(c->server)) + == (char *)0) + OutOfMem(); + pRCTemp->aliases = c->aliases; + c->aliases = (NAMES *)0; + *ppRC = pRCTemp; + ppRC = &pRCTemp->pRCnext; + CONDDEBUG((1, "[%s] remote on %s", c->server, c->master)); + } + return; + } + + /* + * i hope this is right: + * in master during startup, + * pGroupsOld = *empty* + * pGroups = filling with groups of consoles + * pGEstage = *empty* + * in master during reread, + * pGroupsOld = shrinking groups as they move to pGEstage + * pGroups = filling with groups of new consoles + * pGEstage = filling with groups from pGroupsOld + * in slave during reread, + * pGroupsOld = shrinking groups as they move to pGEstage + * pGroups = *empty* + * pGEstage = filling with groups from pGroupsOld + * + * now, pGroups in the slave during a reread may actually be + * temporarily used to hold stuff that's moving to pGEstage. + * in the master it might also have group stubs as well. + * but by the end, if it has anything, it's all empty groups + * in the slave and a mix of real (new) and empty in the master. + */ + if (!isStartup) { + CONSENT **ppCE; + /* hunt for a local match, "pCEmatch != (CONSENT *)0" if found */ + pCEmatch = (CONSENT *)0; + for (pGEmatch = pGroupsOld; pGEmatch != (GRPENT *)0; + pGEmatch = pGEmatch->pGEnext) { + for (ppCE = &pGEmatch->pCElist, pCEmatch = pGEmatch->pCElist; + pCEmatch != (CONSENT *)0; + ppCE = &pCEmatch->pCEnext, pCEmatch = pCEmatch->pCEnext) { + if (strcasecmp(c->server, pCEmatch->server) == 0) { + /* extract pCEmatch from the linked list */ + *ppCE = pCEmatch->pCEnext; + pGEmatch->imembers--; + break; + } + } + if (pCEmatch != (CONSENT *)0) + break; + } + + /* we're a child and we didn't find a match, next! */ + if (!isMaster && (pCEmatch == (CONSENT *)0)) + return; + + /* otherwise....we'll fall through and build a group with a + * single console. at then end we'll do all the hard work + * of shuffling things around, comparing, etc. this way we + * end up with the same parsed/pruned strings in the same + * fields and we don't have to do a lot of the same work here + * (especially the whitespace pruning) + */ + } + + /* ok, we're ready to rock and roll...first, lets make + * sure we have a group to go in and then we'll pop + * out a console and start filling it up + */ + /* let's get going with a group */ + if (pGroups == (GRPENT *)0) { + if ((pGroups = (GRPENT *)calloc(1, sizeof(GRPENT))) + == (GRPENT *)0) + OutOfMem(); + pGE = pGroups; + pGE->pid = -1; + pGE->id = groupID++; + } + + /* if we've filled up the group, get another... + */ + if (cMaxMemb == pGE->imembers) { + if ((pGE->pGEnext = (GRPENT *)calloc(1, sizeof(GRPENT))) + == (GRPENT *)0) + OutOfMem(); + pGE = pGE->pGEnext; + pGE->pid = -1; + pGE->id = groupID++; + } + + /* ok, now for the hard part of the reread */ + if (pCEmatch == (CONSENT *)0) { /* add new console */ + CONSENT **ph = &parserConsoles; + while (*ph != (CONSENT *)0) { + if (*ph == c) { + break; + } else { + ph = &((*ph)->pCEnext); + } + } + + /* if we were in a chain... */ + if (*ph != (CONSENT *)0) { + /* unlink from the chain */ + *ph = c->pCEnext; + /* and possibly fix tail ptr... */ + if (c->pCEnext == (CONSENT *)0) + parserConsolesTail = ph; + } + + /* putting into action, so allocate runtime items */ + if (c->wbuf == (STRING *)0) + c->wbuf = AllocString(); + c->pCEnext = pGE->pCElist; + pGE->pCElist = c; + pGE->imembers++; + } else { /* pCEmatch != (CONSENT *) 0 - modify console */ + short closeMatch = 1; + /* see if the group is already staged */ + for (pGEtmp = pGEstage; pGEtmp != (GRPENT *)0; + pGEtmp = pGEtmp->pGEnext) { + if (pGEtmp->id == pGEmatch->id) + break; + } + + /* if not, allocate one, copy the data, and reset things */ + if (pGEtmp == (GRPENT *)0) { + if ((pGEtmp = + (GRPENT *)calloc(1, sizeof(GRPENT))) == (GRPENT *)0) + OutOfMem(); + + /* copy the data */ + *pGEtmp = *pGEmatch; + + /* don't destroy the fake console */ + pGEmatch->pCEctl = (CONSENT *)0; + + /* prep counters and such */ + pGEtmp->pCElist = (CONSENT *)0; + pGEtmp->pCLall = (CONSCLIENT *)0; + pGEtmp->imembers = 0; + + /* link in to the staging area */ + pGEtmp->pGEnext = pGEstage; + pGEstage = pGEtmp; + + /* fix the free list (the easy one) */ + /* the ppCLbnext link needs to point to the new group */ + if (pGEtmp->pCLfree != (CONSCLIENT *)0) + pGEtmp->pCLfree->ppCLbnext = &pGEtmp->pCLfree; + pGEmatch->pCLfree = (CONSCLIENT *)0; + + if (pGEtmp->pCEctl) { + /* fix the half-logged in clients */ + /* the pCLscan list needs to be rebuilt */ + /* file descriptors need to be watched */ + for (pCLtmp = pGEtmp->pCEctl->pCLon; + pCLtmp != (CONSCLIENT *)0; pCLtmp = pCLtmp->pCLnext) { + /* remove cleanly from the old group */ + if ((CONSCLIENT *)0 != pCLtmp->pCLscan) { + pCLtmp->pCLscan->ppCLbscan = pCLtmp->ppCLbscan; + } + *(pCLtmp->ppCLbscan) = pCLtmp->pCLscan; + /* insert into the new group */ + pCLtmp->pCLscan = pGEtmp->pCLall; + pCLtmp->ppCLbscan = &pGEtmp->pCLall; + if (pCLtmp->pCLscan != (CONSCLIENT *)0) { + pCLtmp->pCLscan->ppCLbscan = &pCLtmp->pCLscan; + } + pGEtmp->pCLall = pCLtmp; + /* set file descriptors */ + FD_SET(FileFDNum(pCLtmp->fd), &rinit); + if (maxfd < FileFDNum(pCLtmp->fd) + 1) + maxfd = FileFDNum(pCLtmp->fd) + 1; + if (!FileBufEmpty(pCLtmp->fd)) + FD_SET(FileFDNum(pCLtmp->fd), &winit); + } + } + } + /* fix the real clients */ + /* the pCLscan list needs to be rebuilt */ + /* file descriptors need to be watched */ + for (pCLtmp = pCEmatch->pCLon; pCLtmp != (CONSCLIENT *)0; + pCLtmp = pCLtmp->pCLnext) { + /* remove cleanly from the old group */ + if ((CONSCLIENT *)0 != pCLtmp->pCLscan) { + pCLtmp->pCLscan->ppCLbscan = pCLtmp->ppCLbscan; + } + *(pCLtmp->ppCLbscan) = pCLtmp->pCLscan; + /* insert into the new group */ + pCLtmp->pCLscan = pGEtmp->pCLall; + pCLtmp->ppCLbscan = &pGEtmp->pCLall; + if (pCLtmp->pCLscan != (CONSCLIENT *)0) { + pCLtmp->pCLscan->ppCLbscan = &pCLtmp->pCLscan; + } + pGEtmp->pCLall = pCLtmp; + /* set file descriptors */ + FD_SET(FileFDNum(pCLtmp->fd), &rinit); + if (maxfd < FileFDNum(pCLtmp->fd) + 1) + maxfd = FileFDNum(pCLtmp->fd) + 1; + if (!FileBufEmpty(pCLtmp->fd)) + FD_SET(FileFDNum(pCLtmp->fd), &winit); + } + + /* add the original console to the new group */ + pCEmatch->pCEnext = pGEtmp->pCElist; + pGEtmp->pCElist = pCEmatch; + pGEtmp->imembers++; + if (pCEmatch->cofile != (CONSFILE *)0) { + int cofile = FileFDNum(pCEmatch->cofile); + FD_SET(cofile, &rinit); + if (maxfd < cofile + 1) + maxfd = cofile + 1; + if (!FileBufEmpty(pCEmatch->cofile)) + FD_SET(cofile, &winit); + } + + /* now check for any changes between pCEmatch & c. + * we can munch the pCEmatch structure 'cause ConsDown() + * doesn't depend on anything we touch here + */ + if (pCEmatch->type != c->type) { + pCEmatch->type = c->type; + closeMatch = 0; + } + if (pCEmatch->logfile != (char *)0 && c->logfile != (char *)0) { + if (strcmp(pCEmatch->logfile, c->logfile) != 0) { + SwapStr(pCEmatch->logfile, c->logfile); + closeMatch = 0; + } + } else if (pCEmatch->logfile != (char *)0 || + c->logfile != (char *)0) { + SwapStr(pCEmatch->logfile, c->logfile); + closeMatch = 0; + } + + switch (pCEmatch->type) { + case EXEC: + if (pCEmatch->exec != (char *)0 && c->exec != (char *)0) { + if (strcmp(pCEmatch->exec, c->exec) != 0) { + SwapStr(pCEmatch->exec, c->exec); + closeMatch = 0; + } + } else if (pCEmatch->exec != (char *)0 || + c->exec != (char *)0) { + SwapStr(pCEmatch->exec, c->exec); + closeMatch = 0; + } + if (pCEmatch->ixany != c->ixany) { + pCEmatch->ixany = c->ixany; + closeMatch = 0; + } + if (pCEmatch->ixon != c->ixon) { + pCEmatch->ixon = c->ixon; + closeMatch = 0; + } + if (pCEmatch->ixoff != c->ixoff) { + pCEmatch->ixoff = c->ixoff; + closeMatch = 0; + } +#if defined(CRTSCTS) + if (pCEmatch->crtscts != c->crtscts) { + pCEmatch->crtscts = c->crtscts; + closeMatch = 0; + } +#endif + break; + case DEVICE: + if (pCEmatch->device != (char *)0 && + c->device != (char *)0) { + if (strcmp(pCEmatch->device, c->device) != 0) { + SwapStr(pCEmatch->device, c->device); + closeMatch = 0; + } + } else if (pCEmatch->device != (char *)0 || + c->device != (char *)0) { + SwapStr(pCEmatch->device, c->device); + closeMatch = 0; + } + if (pCEmatch->baud != c->baud) { + pCEmatch->baud = c->baud; + closeMatch = 0; + } + if (pCEmatch->parity != c->parity) { + pCEmatch->parity = c->parity; + closeMatch = 0; + } + if (pCEmatch->hupcl != c->hupcl) { + pCEmatch->hupcl = c->hupcl; + closeMatch = 0; + } + if (pCEmatch->cstopb != c->cstopb) { + pCEmatch->cstopb = c->cstopb; + closeMatch = 0; + } + if (pCEmatch->ixany != c->ixany) { + pCEmatch->ixany = c->ixany; + closeMatch = 0; + } + if (pCEmatch->ixon != c->ixon) { + pCEmatch->ixon = c->ixon; + closeMatch = 0; + } + if (pCEmatch->ixoff != c->ixoff) { + pCEmatch->ixoff = c->ixoff; + closeMatch = 0; + } +#if defined(CRTSCTS) + if (pCEmatch->crtscts != c->crtscts) { + pCEmatch->crtscts = c->crtscts; + closeMatch = 0; + } +#endif + break; + case HOST: + if (pCEmatch->host != (char *)0 && c->host != (char *)0) { + if (strcasecmp(pCEmatch->host, c->host) != 0) { + SwapStr(pCEmatch->host, c->host); + closeMatch = 0; + } + } else if (pCEmatch->host != (char *)0 || + c->host != (char *)0) { + SwapStr(pCEmatch->host, c->host); + closeMatch = 0; + } + if (pCEmatch->port != c->port) { + pCEmatch->port = c->port; + closeMatch = 0; + } + break; + case UNKNOWN: + break; + } + + /* and now the rest (minus the "runtime" members - see below) */ + pCEmatch->activitylog = c->activitylog; + pCEmatch->breaklog = c->breaklog; + pCEmatch->mark = c->mark; + pCEmatch->nextMark = c->nextMark; + pCEmatch->breakNum = c->breakNum; + pCEmatch->ondemand = c->ondemand; + pCEmatch->striphigh = c->striphigh; + pCEmatch->reinitoncc = c->reinitoncc; + pCEmatch->autoreinit = c->autoreinit; + pCEmatch->unloved = c->unloved; + + /* we have to override the ro/rw lists... */ + /* so first destroy the existing (which point to freed space anyway) */ + DestroyConsentUsers(&(pCEmatch->ro)); + DestroyConsentUsers(&(pCEmatch->rw)); + /* now copy over the new stuff */ + for (u = c->ro; u != (CONSENTUSERS *)0; u = u->next) { + ConsentAddUser(&(pCEmatch->ro), u->user->name); + } + for (u = c->rw; u != (CONSENTUSERS *)0; u = u->next) { + ConsentAddUser(&(pCEmatch->rw), u->user->name); + } + + /* the code above shouldn't touch any of the "runtime" members + * 'cause the ConsDown() code needs to be able to rely on those + * to shut things down. + */ + if (!closeMatch && !isMaster) { + SendClientsMsg(pCEmatch, + "[-- Conserver reconfigured - console reset --]\r\n"); + ConsDown(pCEmatch, FLAGFALSE, FLAGTRUE); } } - BuildString("\\z", &breakList[0]); - BuildString("\\r~^b", &breakList[1]); - BuildString("#.reset -x\\r", &breakList[2]); +} - /* nuke the groups lists (should be a noop, but...) */ - while (pGroups != (GRPENT *) 0) { - pGEtmp = pGroups->pGEnext; - DestroyGroup(pGroups); - pGroups = pGEtmp; - } +void +#if PROTOTYPES +ConsoleDestroy(void) +#else +ConsoleDestroy() +#endif +{ + GRPENT **ppGE = (GRPENT **)0; + GRPENT *pGEtmp = (GRPENT *)0; + CONSENT *c = (CONSENT *)0; + CONSENT *cNext = (CONSENT *)0; + REMOTE *pRCtmp = (REMOTE *)0; - /* nuke the remote consoles */ - while (pRCList != (REMOTE *) 0) { + CONDDEBUG((1, "ConsoleDestroy() [%s:%d]", file, line)); + + /* move aside any existing groups */ + pGroupsOld = pGroups; + pGroups = (GRPENT *)0; + + /* init other trackers */ + pGE = pGEstage = (GRPENT *)0; + + /* nuke the old remote consoles */ + while (pRCList != (REMOTE *)0) { pRCtmp = pRCList->pRCnext; DestroyRemoteConsole(pRCList); pRCList = pRCtmp; } + ppRC = &pRCList; - iLine = 0; - while ((acIn = - (unsigned char *)ReadLine(fp, acInSave, - &iLine)) != (unsigned char *)0) { - char *pcLine, *pcMode, *pcLog, *pcRem, *pcStart, *pcMark, *pcBreak; - char *pcColon; + /* add and reconfigure consoles + * this will potentially adjust parserConsoles/parserConsolesTail + * so we need to peek at the pCEnext pointer ahead of time + */ + for (c = parserConsoles; c != (CONSENT *)0; c = cNext) { + /* time to set some defaults and fix up values */ - acStart = PruneSpace((char *)acIn); + /* default break number */ + if (c->breakNum == 0) + c->breakNum = 1; - if ('%' == acStart[0] && '%' == acStart[1] && '\000' == acStart[2]) { - break; - } - if ((char *)0 != (pcLine = strchr(acStart, '=')) && - ((char *)0 == (pcColon = strchr(acStart, ':')) || - pcColon > pcLine)) { - *pcLine++ = '\000'; - acStart = PruneSpace(acStart); - pcLine = PruneSpace(pcLine); - if (0 == strcmp(acStart, "LOGDIR")) { - BuildString((char *)0, logDirectory); - BuildString(pcLine, logDirectory); - } else if (0 == strcmp(acStart, "TIMESTAMP")) { - BuildString((char *)0, defMark); - if (ParseMark(pcFile, iLine, pcLine, tyme, NULL)) { - BuildString(pcLine, defMark); - } - } else if (0 == strcmp(acStart, "DOMAINHACK")) { - domainHack = 1; - } else if (0 == strncmp(acStart, "BREAK", 5) && - acStart[5] >= '1' && acStart[5] <= '9' && - acStart[6] == '\000') { - Debug(1, "ReadCfg(): BREAK%c found with `%s'", acStart[5], - pcLine); - if (pcLine[0] == '\000') { - BuildString((char *)0, &breakList[acStart[5] - '1']); - } else { - BuildString((char *)0, &breakList[acStart[5] - '1']); - BuildString(pcLine, &breakList[acStart[5] - '1']); - CleanupBreak(acStart[5] - '0'); - } - } else { - Error("%s(%d) unknown variable `%s'", pcFile, iLine, - acStart); - } - continue; - } - if ((char *)0 == (pcLine = strchr(acStart, ':')) || - (char *)0 == (pcMode = strchr(pcLine + 1, ':')) || - (char *)0 == (pcLog = strchr(pcMode + 1, ':'))) { - Error("%s(%d) bad config line `%s'", pcFile, iLine, acIn); - continue; - } - *pcLine++ = '\000'; - *pcMode++ = '\000'; - *pcLog++ = '\000'; - - acStart = PruneSpace(acStart); - - /* before going any further, we might was well check for - * duplicates. gotta do it somewhere, and we only need - * the console name to do it. we have to look through - * the pGroups and pGEstage lists. we don't look at the - * pGroupsOld list 'cause that's where the "to be - * reconfiged" consoles live. - * - * i hope this is right...and why i said what i did above: - * in master during startup, - * pGroupsOld = *empty* - * pGroups = filling with groups of consoles - * pGEstage = *empty* - * in master during reread, - * pGroupsOld = shrinking groups as they move to pGEstage - * pGroups = filling with groups of new consoles - * pGEstage = filling with groups from pGroupsOld - * in slave during reread, - * pGroupsOld = shrinking groups as they move to pGEstage - * pGroups = *empty* - * pGEstage = filling with groups from pGroupsOld - * - * now, pGroups in the slave during a reread may actually be - * temporarily used to hold stuff that's moving to pGEstage. - * in the master it might also have group stubs as well. - * but by the end, if it has anything, it's all empty groups - * in the slave and a mix of real (new) and empty in the master. - */ - /* check for dups in the main area */ - for (pGEtmp = pGroups; pGEtmp != (GRPENT *) 0; - pGEtmp = pGEtmp->pGEnext) { - for (pCEtmp = pGEtmp->pCElist; pCEtmp != (CONSENT *) 0; - pCEtmp = pCEtmp->pCEnext) { - if (pCEtmp->server.used && - strcasecmp(acStart, pCEtmp->server.string) == 0) { - if (isMaster) - Error("%s(%d) duplicate console name `%s'", pcFile, - iLine, acStart); - break; - } - } - if (pCEtmp != (CONSENT *) 0) - break; - } - if (pCEtmp != (CONSENT *) 0) - continue; - /* check for dups in the staged area */ - for (pGEtmp = pGEstage; pGEtmp != (GRPENT *) 0; - pGEtmp = pGEtmp->pGEnext) { - for (pCEtmp = pGEtmp->pCElist; pCEtmp != (CONSENT *) 0; - pCEtmp = pCEtmp->pCEnext) { - if (pCEtmp->server.used && - strcasecmp(acStart, pCEtmp->server.string) == 0) { - if (isMaster) - Error("%s(%d) duplicate console name `%s'", pcFile, - iLine, acStart); - break; - } - } - if (pCEtmp != (CONSENT *) 0) - break; - } - if (pCEtmp != (CONSENT *) 0) - continue; - - pcLine = PruneSpace(pcLine); - pcMode = PruneSpace(pcMode); - pcLog = PruneSpace(pcLog); - - if ((char *)0 != (pcMark = strchr(pcLog, ':'))) { - *pcMark++ = '\000'; - pcLog = PruneSpace(pcLog); - pcMark = PruneSpace(pcMark); - /* Skip null intervals */ - if (pcMark[0] == '\000') - pcMark = (char *)0; + /* go ahead and do the '&' substitution */ + if (c->logfile != (char *)0) { + char *lf; + lf = c->logfile; + ExpandLogfile(c, lf); + free(lf); } - if ((char *)0 == pcMark) { - pcBreak = (char *)0; - } else { - if ((char *)0 != (pcBreak = strchr(pcMark, ':'))) { - *pcBreak++ = '\000'; - pcMark = PruneSpace(pcMark); - pcBreak = PruneSpace(pcBreak); - /* Ignore null specs */ - if (pcMark[0] == '\000') - pcMark = (char *)0; - if (pcBreak[0] == '\000') - pcBreak = (char *)0; - } + /* set the options that default true */ + if (c->autoreinit == FLAGUNKNOWN) + c->autoreinit = FLAGTRUE; + if (c->ixon == FLAGUNKNOWN) + c->ixon = FLAGTRUE; + if (c->ixoff == FLAGUNKNOWN) { + if (c->type == EXEC) + c->ixoff = FLAGFALSE; + else + c->ixoff = FLAGTRUE; } - /* if this server remote? - * (contains an '@host' where host is not us) - * if so just add it to a linked list of remote hosts - * I'm sure most sites will never use this code (ksb) - * Today, I beg to differ ;-) (bryan) - */ - if ((char *)0 != (pcRem = strchr(pcLine, '@'))) { - struct hostent *hpMe; - - *pcRem++ = '\000'; - pcLine = PruneSpace(pcLine); - pcRem = PruneSpace(pcRem); - - if ((struct hostent *)0 == (hpMe = gethostbyname(pcRem))) { - Error("%s(%d): gethostbyname(%s): %s", pcFile, iLine, - pcRem, hstrerror(h_errno)); - continue; - } - if (4 != hpMe->h_length || AF_INET != hpMe->h_addrtype) { - Error - ("ReadCfg(): wrong address size (4 != %d) or address family (%d != %d)", - hpMe->h_length, AF_INET, hpMe->h_addrtype); - continue; - } - - if (0 != -#if HAVE_MEMCMP - memcmp(&acMyAddr.s_addr, hpMe->h_addr, hpMe->h_length) -#else - bcmp(&acMyAddr.s_addr, hpMe->h_addr, hpMe->h_length) + /* set the options that default false */ + if (c->activitylog == FLAGUNKNOWN) + c->activitylog = FLAGFALSE; + if (c->breaklog == FLAGUNKNOWN) + c->breaklog = FLAGFALSE; + if (c->hupcl == FLAGUNKNOWN) + c->hupcl = FLAGFALSE; + if (c->ixany == FLAGUNKNOWN) + c->ixany = FLAGFALSE; + if (c->cstopb == FLAGUNKNOWN) + c->cstopb = FLAGFALSE; +#if defined(CRTSCTS) + if (c->crtscts == FLAGUNKNOWN) + c->crtscts = FLAGFALSE; #endif - ) { - /* the master process just gets this added to the list. - * if it existed as a local console before, it'll be - * pruned later. - */ - if (isMaster) { - REMOTE *pRCTemp; - pRCTemp = (REMOTE *) calloc(1, sizeof(REMOTE)); - if ((REMOTE *) 0 == pRCTemp) { - OutOfMem(); - } - BuildString((char *)0, &pRCTemp->rhost); - BuildString(pcRem, &pRCTemp->rhost); - BuildString((char *)0, &pRCTemp->rserver); - BuildString(acStart, &pRCTemp->rserver); - *ppRC = pRCTemp; - ppRC = &pRCTemp->pRCnext; - Verbose("[%s] remote on %s", acStart, pcRem); - } - continue; - } - } + if (c->ondemand == FLAGUNKNOWN) + c->ondemand = FLAGFALSE; + if (c->reinitoncc == FLAGUNKNOWN) + c->reinitoncc = FLAGFALSE; + if (c->striphigh == FLAGUNKNOWN) + c->striphigh = FLAGFALSE; + if (c->unloved == FLAGUNKNOWN) + c->unloved = FLAGFALSE; - if (!isStartup) { - CONSENT **ppCE; - /* hunt for a local match, "pCEmatch != (CONSENT *)0" if found */ - pCEmatch = (CONSENT *) 0; - for (pGEmatch = pGroupsOld; pGEmatch != (GRPENT *) 0; - pGEmatch = pGEmatch->pGEnext) { - for (ppCE = &pGEmatch->pCElist, pCEmatch = - pGEmatch->pCElist; pCEmatch != (CONSENT *) 0; - ppCE = &pCEmatch->pCEnext, pCEmatch = - pCEmatch->pCEnext) { - if (0 == strcasecmp(acStart, pCEmatch->server.string)) { - /* extract pCEmatch from the linked list */ - *ppCE = pCEmatch->pCEnext; - pGEmatch->imembers--; - break; - } - } - if (pCEmatch != (CONSENT *) 0) - break; - } + /* now let command-line args override things */ + if (fNoautoreup) + c->autoreinit = FLAGFALSE; + if (fNoinit) + c->ondemand = FLAGTRUE; + if (fStrip) + c->striphigh = FLAGTRUE; + if (fReopen) + c->reinitoncc = FLAGTRUE; + if (fAll) + c->unloved = FLAGTRUE; - /* we're a child and we didn't find a match, next! */ - if (!isMaster && (pCEmatch == (CONSENT *) 0)) - continue; - - /* otherwise....we'll fall through and build a group with a - * single console. at then end we'll do all the hard work - * of shuffling things around, comparing, etc. this way we - * end up with the same parsed/pruned strings in the same - * fields and we don't have to do a lot of the same work here - * (especially the whitespace pruning) - */ - } - - /* ok, we're ready to rock and roll...first, lets make - * sure we have a group to go in and then we'll pop - * out a console and start filling it up - */ - /* let's get going with a group */ - if (pGroups == (GRPENT *) 0) { - pGroups = (GRPENT *) calloc(1, sizeof(GRPENT)); - if (pGroups == (GRPENT *) 0) - OutOfMem(); - pGE = pGroups; - pGE->pid = -1; - pGE->id = groupID++; - } - - /* if we've filled up the group, get another... - */ - if (cMaxMemb == pGE->imembers) { - pGE->pGEnext = (GRPENT *) calloc(1, sizeof(GRPENT)); - if (pGE->pGEnext == (GRPENT *) 0) - OutOfMem(); - pGE = pGE->pGEnext; - pGE->pid = -1; - pGE->id = groupID++; - } - - pCE = (CONSENT *) calloc(1, sizeof(CONSENT)); - if (pCE == (CONSENT *) 0) - OutOfMem(); - pCE->pCEnext = pGE->pCElist; - pGE->pCElist = pCE; - pGE->imembers++; - - if (pGE->imembers > cMaxMemb) { - Error - ("%s(%d) group has more than %d members -- but we'll give it a spin - THIS SHOULD NEVER HAPPEN", - pcFile, iLine, cMaxMemb); - } - - /* fill in the console entry - * everything is calloc()ed, so STRING types are ready to rock - */ - - BuildString(acStart, &pCE->server); - - /* - * Here we substitute the console name for any '&' character in the - * logfile name. That way you can just have something like - * "/var/console/&" for each of the conserver.cf entries. - */ - pcStart = pcLog; - while ((char *)0 != (pcRem = strchr(pcStart, '&'))) { - *pcRem = '\000'; - BuildString(pcStart, &pCE->lfile); - BuildString(acStart, &pCE->lfile); - pcStart = pcRem + 1; - } - BuildString(pcStart, &pCE->lfile); - if (logDirectory->used > 1 && pCE->lfile.used > 1 && - *pCE->lfile.string != '/') { - char *p; - BuildTmpString((char *)0); - p = BuildTmpString(pCE->lfile.string); - BuildString((char *)0, &pCE->lfile); - BuildString(logDirectory->string, &pCE->lfile); - BuildStringChar('/', &pCE->lfile); - BuildString(p, &pCE->lfile); - BuildTmpString((char *)0); - } - - if (pcMark) { - ParseMark(pcFile, iLine, pcMark, tyme, pCE); - } else { - ParseMark(pcFile, iLine, defMark->string, tyme, pCE); - } - - pCE->breakType = 1; - if (pcBreak) { - int bt; - bt = atoi(pcBreak); - if (bt > 9 || bt < 0) { - Error("%s(%d) bad break spec `%d'", pcFile, iLine, bt); - } else { - pCE->breakType = bt; - Debug(1, "ReadCfg(): breakType set to %d", pCE->breakType); - } - } - - pCE->ipid = pCE->fdtty = -1; - pCE->fup = pCE->autoReUp = pCE->downHard = 0; - pCE->pCLon = pCE->pCLwr = (CONSCLIENT *) 0; - pCE->fdlog = (CONSFILE *) 0; - - if (pcLine[0] == '!') { - char acOut[100]; - pcLine = PruneSpace(pcLine + 1); - pCE->isNetworkConsole = 1; - pCE->telnetState = 0; - BuildString((char *)0, &pCE->networkConsoleHost); - BuildString(pcLine, &pCE->networkConsoleHost); - pCE->networkConsolePort = atoi(pcMode); - pCE->fvirtual = 0; - BuildString((char *)0, &pCE->dfile); - BuildString(pCE->networkConsoleHost.string, &pCE->dfile); - sprintf(acOut, "/%hu", pCE->networkConsolePort); - BuildString(acOut, &pCE->dfile); - pCE->pbaud = FindBaud("Netwk"); - pCE->pparity = FindParity(" "); - if (isStartup) { - Verbose("[%s] socket on %s logged to %s", acStart, - pCE->dfile.string, pCE->lfile.string); - } - } else if ('|' == pcLine[0]) { - pcLine = PruneSpace(pcLine + 1); - pCE->isNetworkConsole = 0; - pCE->telnetState = 0; - pCE->fvirtual = 1; - BuildString((char *)0, &pCE->pccmd); - BuildString(pcLine, &pCE->pccmd); - BuildString((char *)0, &pCE->dfile); - BuildString("/dev/null", &pCE->dfile); - BuildString((char *)0, &pCE->acslave); - BuildString("/dev/null", &pCE->acslave); - pCE->pbaud = FindBaud("Local"); - pCE->pparity = FindParity(" "); - if (isStartup) { - Verbose("[%s] command `%s' logged to %s", acStart, - pCE->pccmd.string, pCE->lfile.string); - } - } else { - pCE->isNetworkConsole = 0; - pCE->telnetState = 0; - pCE->fvirtual = 0; - BuildString((char *)0, &pCE->dfile); - BuildString(pcLine, &pCE->dfile); - pCE->pbaud = FindBaud(pcMode); - if (pCE->pbaud->irate == 0) { - Error("%s(%d) invalid baud rate `%s'", pcFile, iLine, - pcMode); - DestroyConsent(pGE, pCE); - continue; - } - pCE->pparity = FindParity(pcMode); - if (isStartup) { - Verbose("[%s] %s (%s%c) logged to %s", acStart, - pCE->dfile.string, pCE->pbaud->acrate, - pCE->pparity->ckey, pCE->lfile.string); - } - } - - /* ok, now for the hard part of the reread */ - if (pCEmatch != (CONSENT *) 0) { - short closeMatch = 1; - /* see if the group is already staged */ - for (pGEtmp = pGEstage; pGEtmp != (GRPENT *) 0; - pGEtmp = pGEtmp->pGEnext) { - if (pGEtmp->id == pGEmatch->id) - break; - } - - /* if not, allocate one, copy the data, and reset things */ - if (pGEtmp == (GRPENT *) 0) { - if ((GRPENT *) 0 == - (pGEtmp = (GRPENT *) calloc(1, sizeof(GRPENT)))) - OutOfMem(); - - /* copy the data */ - *pGEtmp = *pGEmatch; - - /* don't destroy the fake console */ - pGEmatch->pCEctl = (CONSENT *) 0; - - /* prep counters and such */ - pGEtmp->pCElist = (CONSENT *) 0; - pGEtmp->pCLall = (CONSCLIENT *) 0; - pGEtmp->imembers = 0; - FD_ZERO(&pGEtmp->rinit); - - /* link in to the staging area */ - pGEtmp->pGEnext = pGEstage; - pGEstage = pGEtmp; - - /* fix the free list (the easy one) */ - /* the ppCLbnext link needs to point to the new group */ - if (pGEtmp->pCLfree != (CONSCLIENT *) 0) - pGEtmp->pCLfree->ppCLbnext = &pGEtmp->pCLfree; - pGEmatch->pCLfree = (CONSCLIENT *) 0; - - if (pGEtmp->pCEctl) { - /* fix the half-logged in clients */ - /* the pCLscan list needs to be rebuilt */ - /* file descriptors need to be watched */ - for (pCLtmp = pGEtmp->pCEctl->pCLon; - pCLtmp != (CONSCLIENT *) 0; - pCLtmp = pCLtmp->pCLnext) { - /* remove cleanly from the old group */ - if ((CONSCLIENT *) 0 != pCLtmp->pCLscan) { - pCLtmp->pCLscan->ppCLbscan = pCLtmp->ppCLbscan; - } - *(pCLtmp->ppCLbscan) = pCLtmp->pCLscan; - /* insert into the new group */ - pCLtmp->pCLscan = pGEtmp->pCLall; - pCLtmp->ppCLbscan = &pGEtmp->pCLall; - if (pCLtmp->pCLscan != (CONSCLIENT *) 0) { - pCLtmp->pCLscan->ppCLbscan = &pCLtmp->pCLscan; - } - pGEtmp->pCLall = pCLtmp; - /* set file descriptors */ - FD_SET(FileFDNum(pCLtmp->fd), &pGEtmp->rinit); - } - } - } - /* fix the real clients */ - /* the pCLscan list needs to be rebuilt */ - /* file descriptors need to be watched */ - for (pCLtmp = pCEmatch->pCLon; pCLtmp != (CONSCLIENT *) 0; - pCLtmp = pCLtmp->pCLnext) { - /* remove cleanly from the old group */ - if ((CONSCLIENT *) 0 != pCLtmp->pCLscan) { - pCLtmp->pCLscan->ppCLbscan = pCLtmp->ppCLbscan; - } - *(pCLtmp->ppCLbscan) = pCLtmp->pCLscan; - /* insert into the new group */ - pCLtmp->pCLscan = pGEtmp->pCLall; - pCLtmp->ppCLbscan = &pGEtmp->pCLall; - if (pCLtmp->pCLscan != (CONSCLIENT *) 0) { - pCLtmp->pCLscan->ppCLbscan = &pCLtmp->pCLscan; - } - pGEtmp->pCLall = pCLtmp; - /* set file descriptors */ - FD_SET(FileFDNum(pCLtmp->fd), &pGEtmp->rinit); - } - - /* add the original console to the new group */ - pCEmatch->pCEnext = pGEtmp->pCElist; - pGEtmp->pCElist = pCEmatch; - pGEtmp->imembers++; - if (pCEmatch->fdtty != -1) { - FD_SET(pCEmatch->fdtty, &pGEtmp->rinit); - } - - /* now check for any changes between pCEmatch & pCE! */ - - if (pCEmatch->isNetworkConsole != pCE->isNetworkConsole || - pCEmatch->fvirtual != pCE->fvirtual) - closeMatch = 0; - if (pCEmatch->dfile.used && pCE->dfile.used) { - if (strcmp(pCEmatch->dfile.string, pCE->dfile.string) != 0) { - BuildString((char *)0, &pCEmatch->dfile); - BuildString(pCE->dfile.string, &pCEmatch->dfile); - if (!pCE->fvirtual) - closeMatch = 0; - } - } else if (pCEmatch->dfile.used || pCE->dfile.used) { - BuildString((char *)0, &pCEmatch->dfile); - BuildString(pCE->dfile.string, &pCEmatch->dfile); - if (!pCE->fvirtual) - closeMatch = 0; - } - if (pCEmatch->lfile.used && pCE->lfile.used) { - if (strcmp(pCEmatch->lfile.string, pCE->lfile.string) != 0) { - BuildString((char *)0, &pCEmatch->lfile); - BuildString(pCE->lfile.string, &pCEmatch->lfile); - FileClose(&pCEmatch->fdlog); - closeMatch = 0; - } - } else if (pCEmatch->lfile.used || pCE->lfile.used) { - BuildString((char *)0, &pCEmatch->lfile); - BuildString(pCE->lfile.string, &pCEmatch->lfile); - FileClose(&pCEmatch->fdlog); - closeMatch = 0; - } - if (pCEmatch->pbaud != pCE->pbaud) { - pCEmatch->pbaud = pCE->pbaud; - closeMatch = 0; - } - if (pCEmatch->pparity != pCE->pparity) { - pCEmatch->pparity = pCE->pparity; - closeMatch = 0; - } - if (pCEmatch->isNetworkConsole != pCE->isNetworkConsole) { - pCEmatch->isNetworkConsole = pCE->isNetworkConsole; - closeMatch = 0; - } - if (pCEmatch->fvirtual != pCE->fvirtual) { - pCEmatch->fvirtual = pCE->fvirtual; - closeMatch = 0; - } - if (pCE->isNetworkConsole) { - if (pCEmatch->networkConsoleHost.used && - pCE->networkConsoleHost.used) { - if (strcasecmp - (pCEmatch->networkConsoleHost.string, - pCE->networkConsoleHost.string) != 0) { - BuildString((char *)0, - &pCEmatch->networkConsoleHost); - BuildString(pCE->networkConsoleHost.string, - &pCEmatch->networkConsoleHost); - closeMatch = 0; - } - } else if (pCEmatch->networkConsoleHost.used || - pCE->networkConsoleHost.used) { - BuildString((char *)0, &pCEmatch->networkConsoleHost); - BuildString(pCE->networkConsoleHost.string, - &pCEmatch->networkConsoleHost); - closeMatch = 0; - } - if (pCEmatch->networkConsolePort != - pCE->networkConsolePort) { - pCEmatch->networkConsolePort = pCE->networkConsolePort; - closeMatch = 0; - } - if (pCEmatch->telnetState != pCE->telnetState) { - pCEmatch->telnetState = pCE->telnetState; - closeMatch = 0; - } - } - if (pCE->fvirtual) { - if (pCEmatch->pccmd.used && pCE->pccmd.used) { - if (strcmp(pCEmatch->pccmd.string, pCE->pccmd.string) - != 0) { - BuildString((char *)0, &pCEmatch->pccmd); - BuildString(pCE->pccmd.string, &pCEmatch->pccmd); - closeMatch = 0; - } - } else if (pCEmatch->pccmd.used || pCE->pccmd.used) { - BuildString((char *)0, &pCEmatch->pccmd); - BuildString(pCE->pccmd.string, &pCEmatch->pccmd); - closeMatch = 0; - } - } - pCEmatch->activitylog = pCE->activitylog; - pCEmatch->breaklog = pCE->breaklog; - pCEmatch->mark = pCE->mark; - pCEmatch->nextMark = pCE->nextMark; - pCEmatch->breakType = pCE->breakType; - pCEmatch->downHard = pCE->downHard; - - if (!closeMatch && !isMaster) { - /* fdtty/fup/fronly/acslave/ipid */ - SendClientsMsg(pCEmatch, - "[-- Conserver reconfigured - console reset --]\r\n"); - ConsDown(pCEmatch, &pGEtmp->rinit, 0); - } - - /* nuke the temp data structure */ - DestroyConsent(pGE, pCE); - } + /* now remember where we're headed and do the dirty work */ + cNext = c->pCEnext; + ConsoleAdd(c); } /* go through and nuke groups (if a child or are empty) */ - for (ppGE = &pGroups; *ppGE != (GRPENT *) 0;) { + for (ppGE = &pGroups; *ppGE != (GRPENT *)0;) { if (!isMaster || (*ppGE)->imembers == 0) { pGEtmp = *ppGE; *ppGE = (*ppGE)->pGEnext; @@ -969,203 +2211,1698 @@ ReadCfg(pcFile, fp, master) ppGE = &((*ppGE)->pGEnext); } } - /* now append the staged groups */ + /* now append the staged groups (old matching groups/consoles) */ *ppGE = pGEstage; - /* nuke the old groups lists */ - while (pGroupsOld != (GRPENT *) 0) { + /* reset the trackers */ + pGE = pGEstage = (GRPENT *)0; + + /* nuke the old groups lists (non-matching groups/consoles) */ + while (pGroupsOld != (GRPENT *)0) { pGEtmp = pGroupsOld->pGEnext; DestroyGroup(pGroupsOld); pGroupsOld = pGEtmp; } - /* nuke the old remote consoles */ - while (pRCListOld != (REMOTE *) 0) { - pRCtmp = pRCListOld->pRCnext; - DestroyRemoteConsole(pRCListOld); - pRCListOld = pRCtmp; - } + while (parserConsoles != (CONSENT *)0) + DestroyParserDefaultOrConsole(parserConsoles, &parserConsoles, + &parserConsolesTail); + DestroyParserDefaultOrConsole(parserConsoleTemp, (CONSENT **)0, + (CONSENT ***)0); + parserConsoles = parserConsoleTemp = (CONSENT *)0; - *ppRC = (REMOTE *) 0; + /* here we check on the client permissions and adjust accordingly */ + if (!isMaster) { + CONSENT *pCE = (CONSENT *)0; + CONSCLIENT *pCL = (CONSCLIENT *)0; + CONSCLIENT *pCLnext = (CONSCLIENT *)0; + int access = -1; - /* clean out the access restrictions - */ - while (pACList != (ACCESS *) 0) { - pACtmp = pACList->pACnext; - DestroyAccessList(pACList); - pACList = pACtmp; - } - pACList = (ACCESS *) 0; - ppAC = &pACList; - - while ((acIn = - (unsigned char *)ReadLine(fp, acInSave, - &iLine)) != (unsigned char *)0) { - char *pcMach, *pcNext, *pcMem; - char cType; - int iLen; - - acStart = PruneSpace((char *)acIn); - - if ('%' == acStart[0] && '%' == acStart[1] && '\000' == acStart[2]) { - break; - } - if ((char *)0 == (pcNext = strchr(acStart, ':'))) { - Error("%s(%d) missing colon?", pcFile, iLine); - continue; - } - - do { - *pcNext++ = '\000'; - } while (isspace((int)(*pcNext))); - - switch (acStart[0]) { - case 'a': /* allowed, allow, allows */ - case 'A': - cType = 'a'; - break; - case 'r': /* rejected, refused, refuse */ - case 'R': - cType = 'r'; - break; - case 't': /* trust, trusted, trusts */ - case 'T': - cType = 't'; - break; - default: - cType = ' '; - Error("%s(%d) unknown access key `%s'", pcFile, iLine, - acStart); - break; - } - if (cType == ' ') - continue; - - while ('\000' != *(pcMach = pcNext)) { - int j, isCIDR = 0; - while ('\000' != *pcNext && - !(isspace((int)(*pcNext)) || ',' == *pcNext)) { - ++pcNext; - } - while ('\000' != *pcNext && - (isspace((int)(*pcNext)) || ',' == *pcNext)) { - *pcNext++ = '\000'; - } - - /* Scan for [0-9./], and stop if you find something else */ - for (j = 0; pcMach[j] != '\000'; j++) { - if (!isdigit((int)(pcMach[j])) && pcMach[j] != '/' && - pcMach[j] != '.') { - break; - } - } - /* Did we see just [0-9./]? If so, CIDR notation */ - if (pcMach[j] == '\000') { - /* Do a little checking on the input */ - int nCount = 0, sCount = 0, dCount = 0; - char *sPtr = (char *)0, *nPtr = (char *)0; - char cidr[BUFSIZ]; - - strcpy(cidr, pcMach); - /* Scan for [0-9./], and stop if you find something else */ - for (j = 0; cidr[j] != '\000'; j++) { - if (isdigit((int)(cidr[j]))) { - if (nPtr == (char *)0) { - nCount++; - nPtr = cidr + j; - } - } else if (cidr[j] == '/') { - sCount++; - sPtr = cidr + j; - } else if (cidr[j] == '.') { - int num; - dCount++; - if (nPtr == (char *)0) { - Error - ("%s(%d) bad access list specification `%s': missing numeral before `.'", - pcFile, iLine, pcMach); - break; - } - cidr[j] = '\000'; - num = atoi(nPtr); - if (num < 0 || num > 255) { - Error - ("%s(%d) bad access list specification `%s': invalid IP octet `%s'", - pcFile, iLine, pcMach, nPtr); - break; - } - nPtr = (char *)0; - } - } - /* If we got through the whole string, then... - * Gotta check against pcMach 'cause we stompped on stuff in cidr above, so can't - * judge what happened correctly with it. - */ - if (pcMach[j] == '\000') { - if (dCount != 3 || sCount > 1) { - Error - ("%s(%d) bad access list specification `%s': must be in a.b.c.d[/n] form", - pcFile, iLine, pcMach); - continue; - } - if (sCount == 1) { - int mask; - mask = atoi(sPtr + 1); - if (mask < 0 || mask > 32) { - Error - ("%s(%d) bad access list specification `%s': netmask not from 0 to 32", - pcFile, iLine, pcMach); - continue; - } - } - isCIDR = 1; - } else { + for (pCE = pGroups->pCElist; pCE != (CONSENT *)0; + pCE = pCE->pCEnext) { + for (pCL = pCE->pCLon; pCL != (CONSCLIENT *)0; pCL = pCLnext) { + pCLnext = pCL->pCLnext; /* in case we drop client */ + access = ClientAccess(pCE, pCL->username->string); + if (access == -1) { + DisconnectClient(pGroups, pCL, + "[Conserver reconfigured - access denied]\r\n", + FLAGFALSE); continue; } + if (pCL->fro == access) + continue; + pCL->fro = access; + if (access) { + FileWrite(pCL->fd, + "[Conserver reconfigured - r/w access removed]\r\n", + -1); + if (pCL->fwr) { + pCL->fwr = 0; + pCL->fwantwr = 0; + TagLogfileAct(pCE, "%s detached", + pCL->acid->string); + if (pCE->nolog) { + pCE->nolog = 0; + TagLogfile(pCE, + "Console logging restored (bumped)"); + } + pCE->pCLwr = FindWrite(pCE->pCLon); + } + } else { + FileWrite(pCL->fd, + "[Conserver reconfigured - r/w access granted]\r\n", + -1); + } } - - if ((ACCESS *) 0 == - (pACtmp = (ACCESS *) calloc(1, sizeof(ACCESS)))) { - OutOfMem(); - } - iLen = strlen(pcMach); - if ((char *)0 == (pcMem = malloc(iLen + 1))) { - OutOfMem(); - } - pACtmp->ctrust = cType; - pACtmp->ilen = iLen; - pACtmp->pcwho = strcpy(pcMem, pcMach); - pACtmp->isCIDR = isCIDR; - *ppAC = pACtmp; - ppAC = &pACtmp->pACnext; } } +} + +CONSENT * +#if PROTOTYPES +FindConsoleName(CONSENT *c, char *id) +#else +FindConsoleName(c, id) + CONSENT *c; + char *id; +#endif +{ + NAMES *a = (NAMES *)0; + for (; c != (CONSENT *)0; c = c->pCEnext) { + if (strcasecmp(id, c->server) == 0) + return c; + for (a = c->aliases; a != (NAMES *)0; a = a->next) + if (strcasecmp(id, a->name) == 0) + return c; + } + return c; +} + +void +#if PROTOTYPES +ConsoleItemAliases(char *id) +#else +ConsoleItemAliases(id) + char *id; +#endif +{ + char *token = (char *)0; + NAMES *name = (NAMES *)0; + CONSENT *c = (CONSENT *)0; + + CONDDEBUG((1, "ConsoleItemAliases(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000')) { + while (parserConsoleTemp->aliases != (NAMES *)0) { + name = parserConsoleTemp->aliases->next; + if (parserConsoleTemp->aliases->name != (char *)0) + free(parserConsoleTemp->aliases->name); + free(parserConsoleTemp->aliases); + parserConsoleTemp->aliases = name; + } + return; + } + for (token = strtok(id, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + if ((c = FindConsoleName(parserConsoles, token)) != (CONSENT *)0) { + if (isMaster) + Error + ("alias name `%s' invalid: already in use by console `%s' [%s:%d]", + token, c->server, file, line); + continue; + } + if ((c = + FindConsoleName(parserConsoleTemp, token)) != (CONSENT *)0) { + if (isMaster) + Error("alias name `%s' repeated: ignored [%s:%d]", token, + file, line); + continue; + } + if ((name = (NAMES *)calloc(1, sizeof(NAMES))) == (NAMES *)0) + OutOfMem(); + if ((name->name = strdup(token)) == (char *)0) + OutOfMem(); + name->next = parserConsoleTemp->aliases; + parserConsoleTemp->aliases = name; + } +} + +void +#if PROTOTYPES +ConsoleItemBaud(char *id) +#else +ConsoleItemBaud(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemBaud(%s) [%s:%d]", id, file, line)); + ProcessBaud(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemBreak(char *id) +#else +ConsoleItemBreak(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemBreak(%s) [%s:%d]", id, file, line)); + ProcessBreak(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemDevice(char *id) +#else +ConsoleItemDevice(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemDevice(%s) [%s:%d]", id, file, line)); + ProcessDevice(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemExec(char *id) +#else +ConsoleItemExec(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemExec(%s) [%s:%d]", id, file, line)); + ProcessExec(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemFlow(char *id) +#else +ConsoleItemFlow(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemFlow(%s) [%s:%d]", id, file, line)); + ProcessFlow(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemHost(char *id) +#else +ConsoleItemHost(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemHost(%s) [%s:%d]", id, file, line)); + ProcessHost(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemInclude(char *id) +#else +ConsoleItemInclude(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemInclude(%s) [%s:%d]", id, file, line)); + ProcessInclude(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemLogfile(char *id) +#else +ConsoleItemLogfile(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemLogfile(%s) [%s:%d]", id, file, line)); + ProcessLogfile(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemMaster(char *id) +#else +ConsoleItemMaster(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemMaster(%s) [%s:%d]", id, file, line)); + ProcessMaster(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemOptions(char *id) +#else +ConsoleItemOptions(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemOptions(%s) [%s:%d]", id, file, line)); + ProcessOptions(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemParity(char *id) +#else +ConsoleItemParity(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemParity(%s) [%s:%d]", id, file, line)); + ProcessParity(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemPort(char *id) +#else +ConsoleItemPort(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemPort(%s) [%s:%d]", id, file, line)); + ProcessPort(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemRo(char *id) +#else +ConsoleItemRo(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemRo(%s) [%s:%d]", id, file, line)); + ProcessRoRw(&(parserConsoleTemp->ro), id); +} + +void +#if PROTOTYPES +ConsoleItemRw(char *id) +#else +ConsoleItemRw(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemRw(%s) [%s:%d]", id, file, line)); + ProcessRoRw(&(parserConsoleTemp->rw), id); +} + +void +#if PROTOTYPES +ConsoleItemTimestamp(char *id) +#else +ConsoleItemTimestamp(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemTimestamp(%s) [%s:%d]", id, file, line)); + ProcessTimestamp(parserConsoleTemp, id); +} + +void +#if PROTOTYPES +ConsoleItemType(char *id) +#else +ConsoleItemType(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemType(%s) [%s:%d]", id, file, line)); + ProcessType(parserConsoleTemp, id); +} + +/* 'access' handling */ +typedef struct parserAccess { + STRING *name; + ACCESS *access; + CONSENTUSERS *admin; + struct parserAccess *next; +} PARSERACCESS; + +PARSERACCESS *parserAccesses = (PARSERACCESS *)0; +PARSERACCESS **parserAccessesTail = &parserAccesses; +PARSERACCESS *parserAccessTemp = (PARSERACCESS *)0; + +void +#if PROTOTYPES +DestroyParserAccess(PARSERACCESS *pa) +#else +DestroyParserAccess(pa) + PARSERACCESS *pa; +#endif +{ + PARSERACCESS **ppa = &parserAccesses; + ACCESS *a = (ACCESS *)0; + char *m = (char *)0; + + if (pa == (PARSERACCESS *)0) + return; + + while (*ppa != (PARSERACCESS *)0) { + if (*ppa == pa) { + break; + } else { + ppa = &((*ppa)->next); + } + } + + BuildTmpString((char *)0); + m = BuildTmpString(pa->name->string); + /* if we were in a chain... */ + if (*ppa != (PARSERACCESS *)0) { + /* unlink from the chain */ + *ppa = pa->next; + /* and possibly fix tail ptr... */ + if (pa->next == (PARSERACCESS *)0) + parserAccessesTail = ppa; + } + DestroyString(pa->name); + for (a = pa->access; a != (ACCESS *)0;) { + ACCESS *n = a->pACnext; + BuildTmpStringChar(','); + m = BuildTmpString(a->pcwho); + DestroyAccessList(a); + a = n; + } + DestroyConsentUsers(&(pa->admin)); + free(pa); + CONDDEBUG((2, "DestroyParserAccess(): %s", m)); +} + +PARSERACCESS * +#if PROTOTYPES +AccessFind(char *id) +#else +AccessFind(id) + char *id; +#endif +{ + PARSERACCESS *pa; + for (pa = parserAccesses; pa != (PARSERACCESS *)0; pa = pa->next) { + if (strcasecmp(id, pa->name->string) == 0) + return pa; + } + return pa; +} + +void +#if PROTOTYPES +AccessAddACL(PARSERACCESS *pa, ACCESS *access) +#else +AccessAddACL(pa, access) + PARSERACCESS *pa; + ACCESS *access; +#endif +{ + ACCESS **ppa = (ACCESS **)0; + ACCESS *new = (ACCESS *)0; + + for (ppa = &(pa->access); *ppa != (ACCESS *)0; + ppa = &((*ppa)->pACnext)) { + if ((*ppa)->ctrust == access->ctrust && + (*ppa)->isCIDR == access->isCIDR && + strcasecmp((*ppa)->pcwho, access->pcwho) == 0) { + return; + } + } + + if ((new = (ACCESS *)calloc(1, sizeof(ACCESS))) + == (ACCESS *)0) + OutOfMem(); + *new = *access; + if ((new->pcwho = strdup(access->pcwho)) + == (char *)0) + OutOfMem(); + /* link into the list at the end */ + new->pACnext = (ACCESS *)0; + *ppa = new; +} + +void +#if PROTOTYPES +AccessBegin(char *id) +#else +AccessBegin(id) + char *id; +#endif +{ + CONDDEBUG((1, "AccessBegin(%s) [%s:%d]", id, file, line)); + if (id == (char *)0 || id[0] == '\000') { + if (isMaster) + Error("empty access name [%s:%d]", file, line); + return; + } + if (parserAccessTemp != (PARSERACCESS *)0) + DestroyParserAccess(parserAccessTemp); + if ((parserAccessTemp = + (PARSERACCESS *)calloc(1, sizeof(PARSERACCESS))) + == (PARSERACCESS *)0) + OutOfMem(); + parserAccessTemp->name = AllocString(); + BuildString(id, parserAccessTemp->name); +} + +void +#if PROTOTYPES +AccessEnd(void) +#else +AccessEnd() +#endif +{ + PARSERACCESS *pa = (PARSERACCESS *)0; + + CONDDEBUG((1, "AccessEnd() [%s:%d]", file, line)); + + if (parserAccessTemp->name->used <= 1) { + DestroyParserAccess(parserAccessTemp); + parserAccessTemp = (PARSERACCESS *)0; + return; + } + + /* if we're overriding an existing group, nuke it */ + if ((pa = + AccessFind(parserAccessTemp->name->string)) != + (PARSERACCESS *)0) { + DestroyParserAccess(pa); + } + + /* add the temp to the tail of the list */ + *parserAccessesTail = parserAccessTemp; + parserAccessesTail = &(parserAccessTemp->next); + parserAccessTemp = (PARSERACCESS *)0; +} + +void +#if PROTOTYPES +AccessAbort(void) +#else +AccessAbort() +#endif +{ + CONDDEBUG((1, "AccessAbort() [%s:%d]", file, line)); + DestroyParserAccess(parserAccessTemp); + parserAccessTemp = (PARSERACCESS *)0; +} + +void +#if PROTOTYPES +AccessDestroy(void) +#else +AccessDestroy() +#endif +{ + ACCESS *a; + PARSERACCESS *p; + ACCESS **ppa; + CONSENTUSERS **pad; + + CONDDEBUG((1, "AccessDestroy() [%s:%d]", file, line)); + + /* clean out the access restrictions */ + while (pACList != (ACCESS *)0) { + a = pACList->pACnext; + DestroyAccessList(pACList); + pACList = a; + } + pACList = (ACCESS *)0; + + DestroyConsentUsers(&(pADList)); + pADList = (CONSENTUSERS *)0; + + ppa = &(pACList); + pad = &(pADList); + + for (p = parserAccesses; p != (PARSERACCESS *)0; p = p->next) { +#if DUMPDATA + Msg("ParserAccess = %s", p->name->string); + for (a = p->access; a != (ACCESS *)0; a = a->pACnext) { + Msg(" Access = %c, %d, %s", a->ctrust, a->isCIDR, a->pcwho); + } + { + CONSENTUSERS *u; + for (u = p->admin; u != (CONSENTUSERS *)0; u = u->next) { + Msg(" Admin = %s", u->user->name); + } + } +#endif + if ((p->name->used == 2 && p->name->string[0] == '*') || + IsMe(p->name->string)) { + CONDDEBUG((1, "AccessDestroy(): adding ACL `%s'", + p->name->string)); + *ppa = p->access; + p->access = (ACCESS *)0; + /* add any admin users to the list */ + if (p->admin != (CONSENTUSERS *)0) { + *pad = p->admin; + p->admin = (CONSENTUSERS *)0; + } + + /* advance to the end of the list so we can append more + * this will potentially have duplicates in the access + * list, but since we're using the first seen, it's more + * overhead, but no big deal + */ + while (*ppa != (ACCESS *)0) { + ppa = &((*ppa)->pACnext); + } + while (*pad != (CONSENTUSERS *)0) { + pad = &((*pad)->next); + } + } + } + + while (parserAccesses != (PARSERACCESS *)0) + DestroyParserAccess(parserAccesses); + DestroyParserAccess(parserAccessTemp); + parserAccesses = parserAccessTemp = (PARSERACCESS *)0; +} + +void +#if PROTOTYPES +AccessItemAdmin(char *id) +#else +AccessItemAdmin(id) + char *id; +#endif +{ + CONDDEBUG((1, "AccessItemAdmin(%s) [%s:%d]", id, file, line)); + ProcessRoRw(&(parserAccessTemp->admin), id); +} + +void +#if PROTOTYPES +AccessItemInclude(char *id) +#else +AccessItemInclude(id) + char *id; +#endif +{ + char *token = (char *)0; + PARSERACCESS *pa = (PARSERACCESS *)0; + + CONDDEBUG((1, "AccessItemInclude(%s) [%s:%d]", id, file, line)); + + if ((id == (char *)0) || (*id == '\000')) + return; + + for (token = strtok(id, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + if ((pa = AccessFind(token)) == (PARSERACCESS *)0) { + if (isMaster) + Error("unknown access name `%s' [%s:%d]", token, file, + line); + } else { + ACCESS *a; + for (a = pa->access; a != (ACCESS *)0; a = a->pACnext) { + AccessAddACL(parserAccessTemp, a); + } + if (pa->admin != (CONSENTUSERS *)0) { + CONSENTUSERS *u; + for (u = pa->admin; u != (CONSENTUSERS *)0; u = u->next) { + ConsentAddUser(&(parserAccessTemp->admin), + u->user->name); + } + } + } + } +} + +void +#if PROTOTYPES +AccessProcessACL(char trust, char *acl) +#else +AccessProcessACL(trust, acl) + char trust; + char *acl; +#endif +{ + char *token = (char *)0; + int i = 0, isCIDR = 0; + int nCount = 0, dCount = 0, sCount = 0, mCount = 0, sPos = 0; + ACCESS **ppa = (ACCESS **)0; + ACCESS *pa = (ACCESS *)0; + in_addr_t addr; +#if HAVE_INET_ATON + struct in_addr inetaddr; +#endif + + /* an empty acl will clear out that type of acl */ + if ((acl == (char *)0) || (*acl == '\000')) { + /* move the old access list aside */ + ACCESS *a = parserAccessTemp->access; + parserAccessTemp->access = (ACCESS *)0; + /* go through the access list */ + while (a != (ACCESS *)0) { + ACCESS *n = a->pACnext; + /* if it's not the trust that we see, add it back */ + if (a->ctrust != trust) + AccessAddACL(parserAccessTemp, a); + /* destroy the old one */ + DestroyAccessList(a); + a = n; + } + } + + for (token = strtok(acl, ALLWORDSEP); token != (char *)0; + token = strtok(NULL, ALLWORDSEP)) { + /* Scan for [0-9./], and stop if you find something else */ + for (i = 0; token[i] != '\000'; i++) { + if (isdigit((int)(token[i]))) { + /* count up digits before and after the slash */ + if (sCount) + nCount++; + else + mCount++; + } else if (token[i] == '/') { + sCount++; + sPos = i; + } else if (token[i] == '.') { + /* if we see non-digits after the slash, cause error */ + if (sCount) + dCount += 10; + dCount++; + } else + break; + } + if (token[i] == '\000') { + /* assuming CIDR notation */ + if (dCount == 3 && + ((sCount == 1 && nCount > 0) || + (sCount == 0 && nCount == 0))) { + if (sCount == 1) { + int mask = atoi(&(token[sPos + 1])); + if (mask < 0 || mask > 255) { + goto cidrerror; + } + token[sPos] = '\000'; + } +#if HAVE_INET_ATON + if (inet_aton(token, &inetaddr) == 0) + goto cidrerror; + addr = inetaddr.s_addr; +#else + addr = inet_addr(token); + if (addr == (in_addr_t) (-1)) + goto cidrerror; +#endif + if (sCount == 1) { + token[sPos] = '/'; + } + } else { + cidrerror: + if (isMaster) + Error("invalid ACL CIDR notation `%s' [%s:%d]", token, + file, line); + return; + } + isCIDR = 1; + } + + /* ok...either a hostname or CIDR notation */ + if ((pa = (ACCESS *)calloc(1, sizeof(ACCESS))) + == (ACCESS *)0) + OutOfMem(); + pa->ctrust = trust; + pa->isCIDR = isCIDR; + if ((pa->pcwho = strdup(token)) + == (char *)0) + OutOfMem(); + + for (ppa = &(parserAccessTemp->access); *ppa != (ACCESS *)0; + ppa = &((*ppa)->pACnext)) { + if ((*ppa)->ctrust == pa->ctrust && + (*ppa)->isCIDR == pa->isCIDR && + strcasecmp((*ppa)->pcwho, pa->pcwho) == 0) { + /* already exists, so skip it */ + DestroyAccessList(pa); + return; + } + } + *ppa = pa; /* add to end of list */ + } +} + +void +#if PROTOTYPES +AccessItemAllowed(char *id) +#else +AccessItemAllowed(id) + char *id; +#endif +{ + CONDDEBUG((1, "AccessItemAllowed(%s) [%s:%d]", id, file, line)); + AccessProcessACL('a', id); +} + +void +#if PROTOTYPES +AccessItemRejected(char *id) +#else +AccessItemRejected(id) + char *id; +#endif +{ + CONDDEBUG((1, "AccessItemRejected(%s) [%s:%d]", id, file, line)); + AccessProcessACL('r', id); +} + +void +#if PROTOTYPES +AccessItemTrusted(char *id) +#else +AccessItemTrusted(id) + char *id; +#endif +{ + CONDDEBUG((1, "AccessItemTrusted(%s) [%s:%d]", id, file, line)); + AccessProcessACL('t', id); +} + +/* 'config' handling */ +CONFIG *parserConfigTemp = (CONFIG *)0; + +void +#if PROTOTYPES +DestroyConfig(CONFIG *c) +#else +DestroyConfig(c) + CONFIG *c; +#endif +{ + if (c == (CONFIG *)0) + return; + if (c->logfile != (char *)0) + free(c->logfile); + if (c->passwdfile != (char *)0) + free(c->passwdfile); + if (c->primaryport != (char *)0) + free(c->primaryport); + if (c->secondaryport != (char *)0) + free(c->secondaryport); +#if HAVE_OPENSSL + if (c->sslcredentials != (char *)0) + free(c->sslcredentials); +#endif + free(c); +} + +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') { + if (isMaster) + 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(); + 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)) { + /* go through and copy over any items seen */ + if (parserConfigTemp->logfile != (char *)0) { + if (pConfig->logfile != (char *)0) + free(pConfig->logfile); + pConfig->logfile = parserConfigTemp->logfile; + parserConfigTemp->logfile = (char *)0; + } + if (parserConfigTemp->passwdfile != (char *)0) { + if (pConfig->passwdfile != (char *)0) + free(pConfig->passwdfile); + pConfig->passwdfile = parserConfigTemp->passwdfile; + parserConfigTemp->passwdfile = (char *)0; + } + if (parserConfigTemp->primaryport != (char *)0) { + if (pConfig->primaryport != (char *)0) + free(pConfig->primaryport); + pConfig->primaryport = parserConfigTemp->primaryport; + parserConfigTemp->primaryport = (char *)0; + } + if (parserConfigTemp->defaultaccess != '\000') + pConfig->defaultaccess = parserConfigTemp->defaultaccess; + if (parserConfigTemp->daemonmode != FLAGUNKNOWN) + pConfig->daemonmode = parserConfigTemp->daemonmode; + if (parserConfigTemp->redirect != FLAGUNKNOWN) + pConfig->redirect = parserConfigTemp->redirect; + if (parserConfigTemp->reinitcheck != 0) + pConfig->reinitcheck = parserConfigTemp->reinitcheck; + if (parserConfigTemp->secondaryport != (char *)0) { + if (pConfig->secondaryport != (char *)0) + free(pConfig->secondaryport); + pConfig->secondaryport = parserConfigTemp->secondaryport; + parserConfigTemp->secondaryport = (char *)0; + } +#if HAVE_OPENSSL + if (parserConfigTemp->sslcredentials != (char *)0) { + if (pConfig->sslcredentials != (char *)0) + free(pConfig->sslcredentials); + pConfig->sslcredentials = parserConfigTemp->sslcredentials; + parserConfigTemp->sslcredentials = (char *)0; + } + if (parserConfigTemp->sslrequired != FLAGUNKNOWN) + pConfig->sslrequired = parserConfigTemp->sslrequired; +#endif + } + } + + 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) + return; + + DestroyConfig(parserConfigTemp); + parserConfigTemp = (CONFIG *)0; +} + +void +#if PROTOTYPES +ConfigItemDefaultaccess(char *id) +#else +ConfigItemDefaultaccess(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemDefaultaccess(%s) [%s:%d]", id, file, line)); + + if (id == (char *)0 || id[0] == '\000') { + parserConfigTemp->defaultaccess = '\000'; + return; + } + if (strcasecmp("allowed", id) == 0) + parserConfigTemp->defaultaccess = 'a'; + else if (strcasecmp("rejected", id) == 0) + parserConfigTemp->defaultaccess = 'r'; + else if (strcasecmp("trusted", id) == 0) + parserConfigTemp->defaultaccess = 't'; + else { + if (isMaster) + Error("invalid access type `%s' [%s:%d]", id, file, line); + } +} + +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 +ConfigItemDaemonmode(char *id) +#else +ConfigItemDaemonmode(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemDaemonmode(%s) [%s:%d]", id, file, line)); + ProcessYesNo(id, &(parserConfigTemp->daemonmode)); +} + +void +#if PROTOTYPES +ConfigItemLogfile(char *id) +#else +ConfigItemLogfile(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemLogfile(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000')) { + if (parserConfigTemp->logfile != (char *)0) { + free(parserConfigTemp->logfile); + parserConfigTemp->logfile = (char *)0; + } + return; + } + if ((parserConfigTemp->logfile = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemPasswordfile(char *id) +#else +ConfigItemPasswordfile(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemPasswordfile(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000')) { + if (parserConfigTemp->passwdfile != (char *)0) { + free(parserConfigTemp->passwdfile); + parserConfigTemp->passwdfile = (char *)0; + } + return; + } + if ((parserConfigTemp->passwdfile = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemPrimaryport(char *id) +#else +ConfigItemPrimaryport(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemPrimaryport(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000')) { + if (parserConfigTemp->primaryport != (char *)0) { + free(parserConfigTemp->primaryport); + parserConfigTemp->primaryport = (char *)0; + } + return; + } + if ((parserConfigTemp->primaryport = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemRedirect(char *id) +#else +ConfigItemRedirect(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemRedirect(%s) [%s:%d]", id, file, line)); + ProcessYesNo(id, &(parserConfigTemp->redirect)); +} + +void +#if PROTOTYPES +ConfigItemReinitcheck(char *id) +#else +ConfigItemReinitcheck(id) + char *id; +#endif +{ + char *p; + + CONDDEBUG((1, "ConfigItemReinitcheck(%s) [%s:%d]", id, file, line)); + + if ((id == (char *)0) || (*id == '\000')) { + parserConfigTemp->reinitcheck = 0; + return; + } + + for (p = id; *p != '\000'; p++) + if (!isdigit((int)(*p))) + break; + + /* if it wasn't a number or the number was zero */ + if (*p != '\000') { + if (isMaster) + Error("invalid reinitcheck value `%s' [%s:%d]", id, file, + line); + return; + } + parserConfigTemp->reinitcheck = atoi(id); +} + +void +#if PROTOTYPES +ConfigItemSecondaryport(char *id) +#else +ConfigItemSecondaryport(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemSecondaryport(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000')) { + if (parserConfigTemp->secondaryport != (char *)0) { + free(parserConfigTemp->secondaryport); + parserConfigTemp->secondaryport = (char *)0; + } + return; + } + if ((parserConfigTemp->secondaryport = strdup(id)) + == (char *)0) + OutOfMem(); +} + +#if HAVE_OPENSSL +void +#if PROTOTYPES +ConfigItemSslcredentials(char *id) +#else +ConfigItemSslcredentials(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemSslcredentials(%s) [%s:%d]", id, file, line)); + if ((id == (char *)0) || (*id == '\000')) { + if (parserConfigTemp->sslcredentials != (char *)0) { + free(parserConfigTemp->sslcredentials); + parserConfigTemp->sslcredentials = (char *)0; + } + return; + } + if ((parserConfigTemp->sslcredentials = strdup(id)) + == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemSslrequired(char *id) +#else +ConfigItemSslrequired(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemSslrequired(%s) [%s:%d]", id, file, line)); + ProcessYesNo(id, &(parserConfigTemp->sslrequired)); +} +#endif + +/* now all the real nitty-gritty bits for making things work */ +ITEM keyBreak[] = { + {"string", BreakItemString}, + {"delay", BreakItemDelay}, + {(char *)0, (void *)0} +}; + +ITEM keyGroup[] = { + {"users", GroupItemUsers}, + {(char *)0, (void *)0} +}; + +ITEM keyDefault[] = { + {"baud", DefaultItemBaud}, + {"break", DefaultItemBreak}, + {"device", DefaultItemDevice}, + {"exec", DefaultItemExec}, +/* {"flow", DefaultItemFlow}, */ + {"host", DefaultItemHost}, + {"include", DefaultItemInclude}, + {"logfile", DefaultItemLogfile}, + {"master", DefaultItemMaster}, + {"options", DefaultItemOptions}, + {"parity", DefaultItemParity}, + {"port", DefaultItemPort}, + {"ro", DefaultItemRo}, + {"rw", DefaultItemRw}, + {"timestamp", DefaultItemTimestamp}, + {"type", DefaultItemType}, + {(char *)0, (void *)0} +}; + +ITEM keyConsole[] = { + {"aliases", ConsoleItemAliases}, + {"baud", ConsoleItemBaud}, + {"break", ConsoleItemBreak}, + {"device", ConsoleItemDevice}, + {"exec", ConsoleItemExec}, +/* {"flow", ConsoleItemFlow}, */ + {"host", ConsoleItemHost}, + {"include", ConsoleItemInclude}, + {"logfile", ConsoleItemLogfile}, + {"master", ConsoleItemMaster}, + {"options", ConsoleItemOptions}, + {"parity", ConsoleItemParity}, + {"port", ConsoleItemPort}, + {"ro", ConsoleItemRo}, + {"rw", ConsoleItemRw}, + {"timestamp", ConsoleItemTimestamp}, + {"type", ConsoleItemType}, + {(char *)0, (void *)0} +}; + +ITEM keyAccess[] = { + {"admin", AccessItemAdmin}, + {"allowed", AccessItemAllowed}, + {"include", AccessItemInclude}, + {"rejected", AccessItemRejected}, + {"trusted", AccessItemTrusted}, + {(char *)0, (void *)0} +}; + +ITEM keyConfig[] = { + {"defaultaccess", ConfigItemDefaultaccess}, + {"daemonmode", ConfigItemDaemonmode}, + {"logfile", ConfigItemLogfile}, + {"passwdfile", ConfigItemPasswordfile}, + {"primaryport", ConfigItemPrimaryport}, + {"redirect", ConfigItemRedirect}, + {"reinitcheck", ConfigItemReinitcheck}, + {"secondaryport", ConfigItemSecondaryport}, +#if HAVE_OPENSSL + {"sslcredentials", ConfigItemSslcredentials}, + {"sslrequired", ConfigItemSslrequired}, +#endif + {(char *)0, (void *)0} +}; + +SECTION sections[] = { + {"break", BreakBegin, BreakEnd, BreakAbort, BreakDestroy, keyBreak}, + {"group", GroupBegin, GroupEnd, GroupAbort, GroupDestroy, keyGroup}, + {"default", DefaultBegin, DefaultEnd, DefaultAbort, DefaultDestroy, + keyDefault}, + {"console", ConsoleBegin, ConsoleEnd, ConsoleAbort, ConsoleDestroy, + keyConsole}, + {"access", AccessBegin, AccessEnd, AccessAbort, AccessDestroy, + keyAccess}, + {"config", ConfigBegin, ConfigEnd, ConfigAbort, ConfigDestroy, + keyConfig}, + {(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 +} 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; + + BuildString((char *)0, word); + while ((c = fgetc(fp)) != EOF) { + if (c == '\n') + (*line)++; + if (comment) { + if (c == '\n') + comment = 0; + 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; + } 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 +ReadCfg(char *filename, FILE *fp) +#else +ReadCfg(filename, fp) + char *filename; + FILE *fp; +#endif +{ + static STRING *word = (STRING *)0; + STATES state = START; + int secIndex = 0; + int keyIndex = 0; + TOKEN token = DONE; + short spaceok = 0; + char *p; + int nextline = 1; /* "next" line number */ + int i; #if HAVE_DMALLOC && DMALLOC_MARK_READCFG - Debug(1, "ReadCfg(): dmalloc / MarkReadCfg"); + unsigned long dmallocMarkReadCfg = 0; +#endif + +#if HAVE_DMALLOC && DMALLOC_MARK_READCFG + dmallocMarkReadCfg = dmalloc_mark(); +#endif + isStartup = (pGroups == (GRPENT *)0 && pRCList == (REMOTE *)0); + + /* inititalize local things */ + if (word == (STRING *)0) + word = AllocString(); + line = 1; + file = filename; + + /* initialize the break lists */ + for (i = 0; i < 9; i++) { + if (breakList[i].seq == (STRING *)0) { + breakList[i].seq = AllocString(); + } else { + BuildString((char *)0, breakList[i].seq); + } + breakList[i].delay = BREAKDELAYDEFAULT; + } + BuildString("\\z", breakList[0].seq); + BuildString("\\r~^b", breakList[1].seq); + BuildString("#.", breakList[2].seq); + BuildString("\\r\\d~\\d^b", breakList[3].seq); + breakList[3].delay = 600; + + /* initialize the user list */ + DestroyUserList(); + + /* initialize the config set */ + if (pConfig != (CONFIG *)0) { + DestroyConfig(pConfig); + pConfig = (CONFIG *)0; + } + if ((pConfig = (CONFIG *)calloc(1, sizeof(CONFIG))) + == (CONFIG *)0) + OutOfMem(); + + /* ready to read in the data */ + while ((token = GetWord(fp, &nextline, spaceok, word)) != DONE) { + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + break; + } + break; + } + switch (state) { + case NAME: + case VALUE: + spaceok = 1; + break; + case KEY: + case LEFTB: + case START: + case SEMI: + spaceok = 0; + break; + } + line = nextline; + } + + /* 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 (nextline = 0; (p = sections[nextline].id) != (char *)0; + nextline++) { + (*sections[nextline].destroy) (); + } + +#if HAVE_DMALLOC && DMALLOC_MARK_READCFG + CONDDEBUG((1, "ReadCfg(): dmalloc / MarkReadCfg")); dmalloc_log_changed(dmallocMarkReadCfg, 1, 0, 1); #endif } -/* Unless otherwise stated, returns the same values as send(2) */ void #if PROTOTYPES -ReReadCfg(void) +ReReadCfg(int fd) #else -ReReadCfg() +ReReadCfg(fd) + int fd; #endif { FILE *fpConfig; - if ((FILE *) 0 == (fpConfig = fopen(pcConfig, "r"))) { - Error("ReReadCfg(): fopen(%s): %s", pcConfig, strerror(errno)); + if ((FILE *)0 == (fpConfig = fopen(pcConfig, "r"))) { + if (isMaster) + Error("ReReadCfg(): fopen(%s): %s", pcConfig, strerror(errno)); return; } + FD_ZERO(&rinit); + FD_ZERO(&winit); + if (fd > 0) { + FD_SET(fd, &rinit); + if (maxfd < fd + 1) + maxfd = fd + 1; + } + ReadCfg(pcConfig, fpConfig); fclose(fpConfig); - if (pGroups == (GRPENT *) 0 && pRCList == (REMOTE *) 0) { + if (pGroups == (GRPENT *)0 && pRCList == (REMOTE *)0) { if (isMaster) { Error("no consoles found in configuration file"); kill(thepid, SIGTERM); /* shoot myself in the head */ @@ -1176,35 +3913,124 @@ ReReadCfg() } } + /* check for changes to master & child values */ + if (optConf->logfile == (char *)0 && pConfig->logfile != (char *)0 && + (config->logfile == (char *)0 || + strcmp(pConfig->logfile, config->logfile) != 0)) { + if (config->logfile != (char *)0) + free(config->logfile); + if ((config->logfile = strdup(pConfig->logfile)) + == (char *)0) + OutOfMem(); + ReopenLogfile(); + } + if (optConf->defaultaccess == '\000' && + pConfig->defaultaccess != '\000' && + pConfig->defaultaccess != config->defaultaccess) { + config->defaultaccess = pConfig->defaultaccess; + /* gets used below by SetDefAccess() */ + } + if (optConf->passwdfile == (char *)0 && + pConfig->passwdfile != (char *)0 && + (config->passwdfile == (char *)0 || + strcmp(pConfig->passwdfile, config->passwdfile) != 0)) { + if (config->passwdfile != (char *)0) + free(config->passwdfile); + if ((config->passwdfile = strdup(pConfig->passwdfile)) + == (char *)0) + OutOfMem(); + /* gets used on-the-fly */ + } + if (optConf->redirect == FLAGUNKNOWN && + pConfig->redirect != FLAGUNKNOWN && + pConfig->redirect != config->redirect) { + config->redirect = pConfig->redirect; + /* gets used on-the-fly */ + } + if (optConf->reinitcheck == 0 && pConfig->reinitcheck != 0 && + pConfig->reinitcheck != config->reinitcheck) { + config->reinitcheck = pConfig->reinitcheck; + /* gets used on-the-fly */ + } +#if HAVE_OPENSSL + if (optConf->sslrequired == FLAGUNKNOWN && + pConfig->sslrequired != FLAGUNKNOWN && + pConfig->sslrequired != config->sslrequired) { + config->sslrequired = pConfig->sslrequired; + /* gets used on-the-fly */ + } +#endif + /* if no one can use us we need to come up with a default */ - if (pACList == (ACCESS *) 0) { - SetDefAccess(&acMyAddr, acMyHost); - } + if (pACList == (ACCESS *)0) + SetDefAccess(myAddrs, myHostname); if (isMaster) { GRPENT *pGE; - CONSENT *pCE; - /* spawn all the children, so fix kids has an initial pid + + /* process any new options (command-line flags might have + * overridden things, so just need to check on new pConfig + * values for changes) */ - for (pGE = pGroups; pGE != (GRPENT *) 0; pGE = pGE->pGEnext) { + if (optConf->daemonmode == FLAGUNKNOWN && + pConfig->daemonmode != FLAGUNKNOWN && + pConfig->daemonmode != config->daemonmode) { + config->daemonmode = pConfig->daemonmode; + Msg("warning: `daemonmode' config option changed - you must restart for it to take effect"); + } + if (optConf->primaryport == (char *)0 && + pConfig->primaryport != (char *)0 && + (config->primaryport == (char *)0 || + strcasecmp(pConfig->primaryport, config->primaryport) != 0)) { + if (config->primaryport != (char *)0) + free(config->primaryport); + if ((config->primaryport = strdup(pConfig->primaryport)) + == (char *)0) + OutOfMem(); + Msg("warning: `primaryport' config option changed - you must restart for it to take effect"); + } + if (optConf->secondaryport == (char *)0 && + pConfig->secondaryport != (char *)0 && + (config->secondaryport == (char *)0 || + strcasecmp(pConfig->secondaryport, + config->secondaryport) != 0)) { + if (config->secondaryport != (char *)0) + free(config->secondaryport); + if ((config->secondaryport = strdup(pConfig->secondaryport)) + == (char *)0) + OutOfMem(); + Msg("warning: `secondaryport' config option changed - you must restart for it to take effect"); + } +#if HAVE_OPENSSL + if (optConf->sslcredentials == (char *)0 && + pConfig->sslcredentials != (char *)0 && + (config->sslcredentials == (char *)0 || + strcasecmp(pConfig->sslcredentials, + config->sslcredentials) != 0)) { + if (config->sslcredentials != (char *)0) + free(config->sslcredentials); + if ((config->sslcredentials = strdup(pConfig->sslcredentials)) + == (char *)0) + OutOfMem(); + Msg("warning: `sslcredentials' config option changed - you must restart for it to take effect"); + } +#endif + + /* spawn all the children, so fix kids has an initial pid */ + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { if (pGE->imembers == 0 || pGE->pid != -1) continue; Spawn(pGE); Verbose("group #%d pid %lu on port %hu", pGE->id, - (unsigned long)pGE->pid, ntohs(pGE->port)); - for (pCE = pGE->pCElist; pCE != (CONSENT *) 0; - pCE = pCE->pCEnext) { - if (-1 != pCE->fdtty) - close(pCE->fdtty); - } + (unsigned long)pGE->pid, pGE->port); } if (fVerbose) { ACCESS *pACtmp; - for (pACtmp = pACList; pACtmp != (ACCESS *) 0; + for (pACtmp = pACList; pACtmp != (ACCESS *)0; pACtmp = pACtmp->pACnext) { Verbose("access type `%c' for `%s'", pACtmp->ctrust, pACtmp->pcwho); @@ -1217,8 +4043,8 @@ ReReadCfg() */ if (fVerbose) { REMOTE *pRC; - for (pRC = pRCUniq; (REMOTE *) 0 != pRC; pRC = pRC->pRCuniq) { - Verbose("peer server on `%s'", pRC->rhost.string); + for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { + Verbose("peer server on `%s'", pRC->rhost); } } } diff --git a/conserver/readcfg.h b/conserver/readcfg.h index 1734c9d..18a9d49 100644 --- a/conserver/readcfg.h +++ b/conserver/readcfg.h @@ -1,50 +1,46 @@ /* - * $Id: readcfg.h,v 5.23 2003-03-06 10:13:41-08 bryan Exp $ + * $Id: readcfg.h,v 5.31 2003-08-21 15:02:16-07 bryan Exp $ * * Copyright conserver.com, 2000 * * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) - * - * Copyright GNAC, Inc., 1998 */ -/* - * Copyright 1992 Purdue Research Foundation, West Lafayette, Indiana - * 47907. All rights reserved. - * - * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb - * - * This software is not subject to any license of the American Telephone - * and Telegraph Company or the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on - * any computer system, and to alter it and redistribute it freely, subject - * to the following restrictions: - * - * 1. Neither the authors nor Purdue University are responsible for any - * consequences of the use of this software. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Credit to the authors and Purdue - * University must appear in documentation and sources. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 4. This notice may not be removed or altered. - */ +typedef struct config { + STRING *name; + char defaultaccess; + FLAG daemonmode; + char *logfile; + char *passwdfile; + char *primaryport; + FLAG redirect; + int reinitcheck; + char *secondaryport; +#if HAVE_OPENSSL + char *sslcredentials; + FLAG sslrequired; +#endif +} CONFIG; -/* we read in which hosts to trust and which ones we proxy for - * from a file, into these structures - */ +typedef struct breaks { + STRING *seq; + int delay; +} BREAKS; -extern GRPENT *pGroups; /* group info */ +extern NAMES *userList; /* user list */ +extern GRPENT *pGroups; /* group info */ extern REMOTE *pRCList; /* list of remote consoles we know about */ extern REMOTE *pRCUniq; /* list of uniq console servers */ -extern ACCESS *pACList; /* `who do you love' (or trust) */ -extern STRING *breakList; /* list of break sequences */ +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 void ReadCfg PARAMS((char *, FILE *)); -extern char *PruneSpace PARAMS((char *)); -extern void ReReadCfg PARAMS((void)); +extern void ReReadCfg PARAMS((int)); extern void DestroyBreakList PARAMS((void)); +extern void DestroyUserList PARAMS((void)); +extern void DestroyConfig PARAMS((CONFIG *)); +extern NAMES *FindUserList PARAMS((char *)); +extern NAMES *AddUserList PARAMS((char *)); +extern CONSENT *FindConsoleName PARAMS((CONSENT *, char *)); diff --git a/conserver/util.c b/conserver/util.c index 20d0659..424eacf 100644 --- a/conserver/util.c +++ b/conserver/util.c @@ -1,22 +1,13 @@ /* - * $Id: util.c,v 1.75 2003-04-06 05:29:35-07 bryan Exp $ + * $Id: util.c,v 1.98 2003-08-24 10:40:10-07 bryan Exp $ * * Copyright conserver.com, 2000 * * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) */ -#include - -#include -#include -#include -#include -#include -#include -#include - #include + #include #if HAVE_OPENSSL @@ -24,13 +15,20 @@ #endif -int fVerbose = 0; +int fVerbose = 0, fErrorPrinted = 0; int isMultiProc = 0; char *progname = "conserver package"; pid_t thepid = 0; int fDebug = 0; -STRING *allStrings = (STRING *) 0; +STRING *allStrings = (STRING *)0; int stringCount = 0; /* count of allStrings list */ +struct in_addr *myAddrs = (struct in_addr *)0; +char myHostname[MAXHOSTNAME]; /* staff.cc.purdue.edu */ +fd_set rinit; +fd_set winit; +int maxfd = 0; +int debugLineNo = 0; +char *debugFileName = (char *)0; /* in the routines below (the init code) we can bomb if malloc fails (ksb) */ @@ -71,7 +69,7 @@ Bye(status) */ const char * #if PROTOTYPES -StrTime(time_t * ltime) +StrTime(time_t *ltime) #else StrTime(ltime) time_t *ltime; @@ -80,7 +78,7 @@ StrTime(ltime) static char curtime[25]; time_t tyme; - tyme = time((time_t *) 0); + tyme = time((time_t *)0); strcpy(curtime, ctime(&tyme)); curtime[24] = '\000'; if (ltime != NULL) @@ -88,31 +86,11 @@ StrTime(ltime) return (const char *)curtime; } -void -#if PROTOTYPES -CheckRW(int fd, int *r, int *w) -#else -CheckRW(fd, r, w) - int fd, int *r, int *w; -#endif -{ - fd_set rfd, wfd; - struct timeval t = { 0, 0 }; - - FD_ZERO(&rfd); - FD_ZERO(&wfd); - FD_SET(fd, &rfd); - FD_SET(fd, &wfd); - select(fd, &rfd, &wfd, (fd_set *) 0, &t); - *r = FD_ISSET(fd, &rfd); - *w = FD_ISSET(fd, &wfd); -} - #define STRING_ALLOC_SIZE 64 char * #if PROTOTYPES -BuildStringChar(const char ch, STRING * msg) +BuildStringChar(const char ch, STRING *msg) #else BuildStringChar(ch, msg) const char ch; @@ -127,28 +105,29 @@ BuildStringChar(ch, msg) msg->allocated += STRING_ALLOC_SIZE * sizeof(char); msg->string = (char *)realloc(msg->string, msg->allocated); } - Debug(3, "BuildStringChar(): 0x%lx tried allocating %lu bytes", - (void *)msg, msg->allocated); + CONDDEBUG((3, + "BuildStringChar(): 0x%lx tried allocating %lu bytes", + (void *)msg, msg->allocated)); if (msg->string == (char *)0) OutOfMem(); } if (msg->used) { msg->string[msg->used - 1] = ch; /* overwrite NULL and */ msg->string[msg->used++] = '\000'; /* increment by one */ - Debug(3, "BuildStringChar(): 0x%lx added 1 char (%d/%d now)", - (void *)msg, msg->used, msg->allocated); + CONDDEBUG((3, "BuildStringChar(): 0x%lx added 1 char (%d/%d now)", + (void *)msg, msg->used, msg->allocated)); } else { msg->string[msg->used++] = ch; /* no NULL, so store stuff */ msg->string[msg->used++] = '\000'; /* and increment by two */ - Debug(3, "BuildStringChar(): 0x%lx added 2 chars (%d/%d now)", - (void *)msg, msg->used, msg->allocated); + CONDDEBUG((3, "BuildStringChar(): 0x%lx added 2 chars (%d/%d now)", + (void *)msg, msg->used, msg->allocated)); } return msg->string; } char * #if PROTOTYPES -BuildString(const char *str, STRING * msg) +BuildString(const char *str, STRING *msg) #else BuildString(str, msg) const char *str; @@ -161,7 +140,7 @@ BuildString(str, msg) msg->used = 0; if (msg->string != (char *)0) msg->string[0] = '\000'; - Debug(3, "BuildString(): 0x%lx reset", (void *)msg); + CONDDEBUG((3, "BuildString(): 0x%lx reset", (void *)msg)); return msg->string; } len = strlen(str) + 1; @@ -177,8 +156,8 @@ BuildString(str, msg) 1) * STRING_ALLOC_SIZE * sizeof(char); msg->string = (char *)realloc(msg->string, msg->allocated); } - Debug(3, "BuildString(): 0x%lx tried allocating %lu bytes", - (void *)msg, msg->allocated); + CONDDEBUG((3, "BuildString(): 0x%lx tried allocating %lu bytes", + (void *)msg, msg->allocated)); if (msg->string == (char *)0) OutOfMem(); } @@ -190,14 +169,100 @@ BuildString(str, msg) if (msg->used) len--; msg->used += len; - Debug(3, "BuildString(): 0x%lx added %d chars (%d/%d now)", - (void *)msg, len, msg->used, msg->allocated); + CONDDEBUG((3, "BuildString(): 0x%lx added %d chars (%d/%d now)", + (void *)msg, len, msg->used, msg->allocated)); + return msg->string; +} + +char * +#if PROTOTYPES +BuildStringN(const char *str, int n, STRING *msg) +#else +BuildStringN(str, n, msg) + const char *str; + int n; + STRING *msg; +#endif +{ + int len; + + if ((char *)0 == str) { + msg->used = 0; + if (msg->string != (char *)0) + msg->string[0] = '\000'; + CONDDEBUG((3, "BuildStringN(): 0x%lx reset", (void *)msg)); + return msg->string; + } + if (n <= 0) + return msg->string; + len = strlen(str) + 1; + if (len > n) { /* if we're a substring */ + len = n; + if (str[n - 1] != '\000') /* if we aren't copying a '\000', */ + len++; /* we need to add one at the end */ + } + if (msg->used + len >= msg->allocated) { + if (0 == msg->allocated) { + msg->allocated = + (len / STRING_ALLOC_SIZE + + 1) * STRING_ALLOC_SIZE * sizeof(char); + msg->string = (char *)calloc(1, msg->allocated); + } else { + msg->allocated += + ((msg->used + len - msg->allocated) / STRING_ALLOC_SIZE + + 1) * STRING_ALLOC_SIZE * sizeof(char); + msg->string = (char *)realloc(msg->string, msg->allocated); + } + CONDDEBUG((3, "BuildStringN(): 0x%lx tried allocating %lu bytes", + (void *)msg, msg->allocated)); + if (msg->string == (char *)0) + OutOfMem(); + } +#if HAVE_MEMCPY + memcpy(msg->string + (msg->used ? msg->used - 1 : 0), str, len); +#else + bcopy(str, msg->string + (msg->used ? msg->used - 1 : 0), len); +#endif + if (len > n) /* we need to terminate the string */ + msg->string[(msg->used ? msg->used - 1 : 0) + len - 1] = '\000'; + if (msg->used) + len--; + msg->used += len; + CONDDEBUG((3, "BuildStringN(): 0x%lx added %d chars (%d/%d now)", + (void *)msg, len, msg->used, msg->allocated)); + return msg->string; +} + +char * +#if PROTOTYPES +ShiftString(STRING *msg, int n) +#else +ShiftString(msg, n) + STRING *msg; + int n; +#endif +{ + if (msg == (STRING *)0 || n <= 0 || n > msg->used - 1) + return (char *)0; + +#if HAVE_MEMMOVE + memmove(msg->string, msg->string + n, msg->used - n); +#else + { + char *s, *e; + int len; + for (s = msg->string, e = s + n, len = msg->used - n; len > 0; + len--) + *s++ = *e++; + } +#endif + msg->used -= n; return msg->string; } void #if PROTOTYPES -InitString(STRING * msg) +InitString(STRING *msg) #else InitString(msg) STRING *msg; @@ -209,31 +274,32 @@ InitString(msg) void #if PROTOTYPES -DestroyString(STRING * msg) +DestroyString(STRING *msg) #else DestroyString(msg) STRING *msg; #endif { - if (msg->prev == (STRING *) 0 && msg->next == (STRING *) 0 && + if (msg->prev == (STRING *)0 && msg->next == (STRING *)0 && allStrings != msg) { - Debug(1, "DestroyString(): 0x%lx non-pooled string destroyed", - (void *)msg, stringCount); + CONDDEBUG((1, "DestroyString(): 0x%lx non-pooled string destroyed", + (void *)msg, stringCount)); } else { - if (msg->prev != (STRING *) 0) + if (msg->prev != (STRING *)0) msg->prev->next = msg->next; - if (msg->next != (STRING *) 0) + if (msg->next != (STRING *)0) msg->next->prev = msg->prev; if (msg == allStrings) { allStrings = msg->next; } stringCount--; - Debug(1, "DestroyString(): 0x%lx string destroyed (count==%d)", - (void *)msg, stringCount); + CONDDEBUG((1, + "DestroyString(): 0x%lx string destroyed (count==%d)", + (void *)msg, stringCount)); } if (msg->allocated) free(msg->string); - InitString(msg); + free(msg); } STRING * @@ -244,18 +310,18 @@ AllocString() #endif { STRING *s; - s = (STRING *) calloc(1, sizeof(STRING)); - if (s == (STRING *) 0) + if ((s = (STRING *)calloc(1, sizeof(STRING))) + == (STRING *)0) OutOfMem(); - if (allStrings != (STRING *) 0) { + if (allStrings != (STRING *)0) { allStrings->prev = s; s->next = allStrings; } allStrings = s; InitString(s); stringCount++; - Debug(1, "AllocString(): 0x%lx created string #%d", (void *)s, - stringCount); + CONDDEBUG((1, "AllocString(): 0x%lx created string #%d", (void *)s, + stringCount)); return s; } @@ -266,14 +332,12 @@ DestroyStrings(void) DestroyStrings() #endif { - while (allStrings != (STRING *) 0) { - STRING *s = allStrings; + while (allStrings != (STRING *)0) { DestroyString(allStrings); - free(s); } } -static STRING *mymsg = (STRING *) 0; +static STRING *mymsg = (STRING *)0; char * #if PROTOTYPES @@ -283,7 +347,7 @@ BuildTmpString(str) const char *str; #endif { - if (mymsg == (STRING *) 0) + if (mymsg == (STRING *)0) mymsg = AllocString(); return BuildString(str, mymsg); } @@ -296,14 +360,14 @@ BuildTmpStringChar(c) const char c; #endif { - if (mymsg == (STRING *) 0) + if (mymsg == (STRING *)0) mymsg = AllocString(); return BuildStringChar(c, mymsg); } char * #if PROTOTYPES -ReadLine(FILE * fp, STRING * save, int *iLine) +ReadLine(FILE *fp, STRING *save, int *iLine) #else ReadLine(fp, save, iLine) FILE *fp; @@ -315,12 +379,12 @@ ReadLine(fp, save, iLine) char *wholeline = (char *)0; char *ret = (char *)0; int i, buflen, peek, commentCheck = 1, comment = 0; - static STRING *bufstr = (STRING *) 0; - static STRING *wholestr = (STRING *) 0; + static STRING *bufstr = (STRING *)0; + static STRING *wholestr = (STRING *)0; - if (bufstr == (STRING *) 0) + if (bufstr == (STRING *)0) bufstr = AllocString(); - if (wholestr == (STRING *) 0) + if (wholestr == (STRING *)0) wholestr = AllocString(); peek = 0; wholeline = (char *)0; @@ -392,8 +456,8 @@ ReadLine(fp, save, iLine) wholeline = BuildString(bufstr->string, wholestr); } - Debug(1, "ReadLine(): returning <%s>", - (wholeline != (char *)0) ? wholeline : ""); + CONDDEBUG((1, "ReadLine(): returning <%s>", + (wholeline != (char *)0) ? wholeline : "")); return wholeline; } @@ -402,7 +466,7 @@ ReadLine(fp, save, iLine) */ char * #if PROTOTYPES -FmtCtl(int ci, STRING * pcIn) +FmtCtl(int ci, STRING *pcIn) #else FmtCtl(ci, pcIn) int ci; @@ -435,7 +499,7 @@ FmtCtl(ci, pcIn) void #if PROTOTYPES -FmtCtlStr(char *pcIn, int len, STRING * pcOut) +FmtCtlStr(char *pcIn, int len, STRING *pcOut) #else FmtCtlStr(pcIn, len, pcOut) char *pcIn; @@ -476,18 +540,21 @@ Debug(level, fmt, va_alist) #endif { va_list ap; + + if (fDebug < level) + return; #if PROTOTYPES va_start(ap, fmt); #else va_start(ap); #endif - if (fDebug < level) - return; if (isMultiProc) - fprintf(stderr, "[%s] %s (%lu): DEBUG: ", StrTime(NULL), progname, - (unsigned long)thepid); + fprintf(stderr, "[%s] %s (%lu): DEBUG: [%s:%d] ", + StrTime((time_t *)0), progname, (unsigned long)thepid, + debugFileName, debugLineNo); else - fprintf(stderr, "%s: DEBUG: ", progname); + fprintf(stderr, "%s: DEBUG: [%s:%d] ", progname, debugFileName, + debugLineNo); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -509,13 +576,14 @@ Error(fmt, va_alist) va_start(ap); #endif if (isMultiProc) - fprintf(stderr, "[%s] %s (%lu): ERROR: ", StrTime(NULL), progname, - (unsigned long)thepid); + fprintf(stderr, "[%s] %s (%lu): ERROR: ", StrTime((time_t *)0), + progname, (unsigned long)thepid); else fprintf(stderr, "%s: ", progname); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); + fErrorPrinted = 1; } void @@ -534,7 +602,7 @@ Msg(fmt, va_alist) va_start(ap); #endif if (isMultiProc) - fprintf(stdout, "[%s] %s (%lu): ", StrTime(NULL), progname, + fprintf(stdout, "[%s] %s (%lu): ", StrTime((time_t *)0), progname, (unsigned long)thepid); else fprintf(stdout, "%s: ", progname); @@ -563,8 +631,8 @@ Verbose(fmt, va_alist) va_start(ap); #endif if (isMultiProc) - fprintf(stdout, "[%s] %s (%lu): INFO: ", StrTime(NULL), progname, - (unsigned long)thepid); + fprintf(stdout, "[%s] %s (%lu): INFO: ", StrTime((time_t *)0), + progname, (unsigned long)thepid); else fprintf(stdout, "%s: ", progname); vfprintf(stdout, fmt, ap); @@ -625,7 +693,7 @@ GetMaxFiles() mf = (FD_SETSIZE - 1); } #endif - Debug(1, "GetMaxFiles(): maxfiles=%d", mf); + CONDDEBUG((1, "GetMaxFiles(): maxfiles=%d", mf)); return mf; } @@ -647,24 +715,25 @@ FileOpenFD(fd, type) { CONSFILE *cfp; - cfp = (CONSFILE *) calloc(1, sizeof(CONSFILE)); - if ((CONSFILE *) 0 == cfp) + if ((cfp = (CONSFILE *)calloc(1, sizeof(CONSFILE))) + == (CONSFILE *)0) OutOfMem(); cfp->ftype = type; cfp->fd = fd; + cfp->wbuf = AllocString(); #if HAVE_OPENSSL - cfp->ssl = (SSL *) 0; - cfp->waitonWrite = cfp->waitonRead = 0; + cfp->ssl = (SSL *)0; + cfp->waitForRead = cfp->waitForWrite = FLAGFALSE; #endif - Debug(2, "FileOpenFD(): encapsulated fd %d type %d", fd, type); + CONDDEBUG((2, "FileOpenFD(): encapsulated fd %d type %d", fd, type)); return cfp; } /* This is to "unencapsulate" the file descriptor */ int #if PROTOTYPES -FileUnopen(CONSFILE * cfp) +FileUnopen(CONSFILE *cfp) #else FileUnopen(cfp) CONSFILE *cfp; @@ -688,7 +757,7 @@ FileUnopen(cfp) retval = -1; break; } - Debug(2, "FileUnopen(): unopened fd %d", cfp->fd); + CONDDEBUG((2, "FileUnopen(): unopened fd %d", cfp->fd)); free(cfp); return retval; @@ -711,20 +780,21 @@ FileOpen(path, flag, mode) int fd; if (-1 == (fd = open(path, flag, mode))) { - Debug(2, "FileOpen(): failed to open `%s'", path); - return (CONSFILE *) 0; + CONDDEBUG((2, "FileOpen(): failed to open `%s'", path)); + return (CONSFILE *)0; } - cfp = (CONSFILE *) calloc(1, sizeof(CONSFILE)); - if ((CONSFILE *) 0 == cfp) + if ((cfp = (CONSFILE *)calloc(1, sizeof(CONSFILE))) + == (CONSFILE *)0) OutOfMem(); cfp->ftype = simpleFile; cfp->fd = fd; + cfp->wbuf = AllocString(); #if HAVE_OPENSSL - cfp->ssl = (SSL *) 0; - cfp->waitonWrite = cfp->waitonRead = 0; + cfp->ssl = (SSL *)0; + cfp->waitForRead = cfp->waitForWrite = FLAGFALSE; #endif - Debug(2, "FileOpen(): opened `%s' as fd %d", path, fd); + CONDDEBUG((2, "FileOpen(): opened `%s' as fd %d", path, fd)); return cfp; } @@ -734,48 +804,42 @@ FileOpen(path, flag, mode) */ int #if PROTOTYPES -FileClose(CONSFILE ** pcfp) +FileClose(CONSFILE **pcfp) #else -FileClose(cfp) +FileClose(pcfp) CONSFILE **pcfp; #endif { CONSFILE *cfp; int retval = 0; #if defined(__CYGWIN__) - int client_sock_flags; struct linger lingeropt; #endif -#if HAVE_OPENSSL - int sflags; -#endif cfp = *pcfp; - if (cfp == (CONSFILE *) 0) + if (cfp == (CONSFILE *)0) return 0; switch (cfp->ftype) { case simpleFile: - retval = close(cfp->fd); + do { + retval = close(cfp->fd); + } while (retval == -1 && errno == EINTR); break; case simpleSocket: #if defined(__CYGWIN__) /* flush out the client socket - set it to blocking, * then write to it */ - client_sock_flags = fcntl(cfp->fd, F_GETFL, 0); - if (client_sock_flags != -1) - /* enable blocking */ - fcntl(cfp->fd, F_SETFL, client_sock_flags & ~O_NONBLOCK); + SetFlags(cfp->fd, 0, O_NONBLOCK) - /* sent it a byte - guaranteed to block - ensure delivery - * of prior data yeah - this is a bit paranoid - try - * without this at first - */ - /* write(cfp->fd, "\n", 1); */ - - /* this is the guts of the workaround for Winsock close bug */ - shutdown(cfp->fd, 1); + /* sent it a byte - guaranteed to block - ensure delivery + * of prior data yeah - this is a bit paranoid - try + * without this at first + */ + /* write(cfp->fd, "\n", 1); */ + /* this is the guts of the workaround for Winsock close bug */ + shutdown(cfp->fd, 1); /* enable lingering */ lingeropt.l_onoff = 1; @@ -783,31 +847,20 @@ FileClose(cfp) setsockopt(cfp->fd, SOL_SOCKET, SO_LINGER, &lingeropt, sizeof(lingeropt)); #endif - retval = close(cfp->fd); - + do { + retval = close(cfp->fd); + } while (retval == -1 && errno == EINTR); break; #if HAVE_OPENSSL case SSLSocket: - sflags = fcntl(cfp->fd, F_GETFL, 0); - if (sflags != -1) { - Debug(2, - "FileClose(): setting socket to BLOCKING on fd %d", - cfp->fd); - fcntl(cfp->fd, F_SETFL, sflags & ~O_NONBLOCK); - } - Debug(2, "FileClose(): performing a SSL_shutdown() on fd %d", - cfp->fd); + CONDDEBUG((2, + "FileClose(): performing a SSL_shutdown() on fd %d", + cfp->fd)); SSL_shutdown(cfp->ssl); - Debug(2, "FileClose(): performing a SSL_free() on fd %d", - cfp->fd); + CONDDEBUG((2, "FileClose(): performing a SSL_free() on fd %d", + cfp->fd)); SSL_free(cfp->ssl); - if (sflags != -1) { - Debug(2, - "FileClose(): restoring socket blocking mode on fd %d", - cfp->fd); - fcntl(cfp->fd, F_SETFL, sflags); - } /* set the sucker back to a simpleSocket and recall so we * do all that special stuff we oh so love...and make sure * we return so we don't try and free(0). -bryan @@ -819,17 +872,19 @@ FileClose(cfp) retval = -1; break; } - Debug(2, "FileClose(): closed fd %d", cfp->fd); + + CONDDEBUG((2, "FileClose(): closed fd %d", cfp->fd)); + DestroyString(cfp->wbuf); free(cfp); - *pcfp = (CONSFILE *) 0; + *pcfp = (CONSFILE *)0; return retval; } -/* Unless otherwise stated, returns the same values as read(2) */ +/* returns: -1 on error or eof, >= 0 for valid reads */ int #if PROTOTYPES -FileRead(CONSFILE * cfp, void *buf, int len) +FileRead(CONSFILE *cfp, void *buf, int len) #else FileRead(cfp, buf, len) CONSFILE *cfp; @@ -837,161 +892,66 @@ FileRead(cfp, buf, len) int len; #endif { - int retval = 0; -#if HAVE_OPENSSL - /*int r, w; */ - int sflags; -#endif + int retval = -1; switch (cfp->ftype) { case simpleFile: case simpleSocket: - retval = read(cfp->fd, buf, len); + while (retval < 0) { + if ((retval = read(cfp->fd, buf, len)) <= 0) { + if (retval == 0) { + retval = -1; + break; + } + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + /* must be non-blocking - so stop */ + retval = 0; + break; + } + Error("FileRead(): fd %d: %s", cfp->fd, + strerror(errno)); + retval = -1; + break; + } + } break; #if HAVE_OPENSSL case SSLSocket: - /*CheckRW(cfp->fd, &r, &w); */ - sflags = fcntl(cfp->fd, F_GETFL, 0); - if (sflags != -1) { - Debug(2, "FileRead(): setting socket to BLOCKING on fd %d", - cfp->fd); - fcntl(cfp->fd, F_SETFL, sflags & ~O_NONBLOCK); + if (cfp->waitForWrite == FLAGTRUE) { + cfp->waitForWrite = FLAGFALSE; + if (cfp->wbuf->used <= 1) + FD_CLR(cfp->fd, &winit); } retval = SSL_read(cfp->ssl, buf, len); switch (SSL_get_error(cfp->ssl, retval)) { case SSL_ERROR_NONE: break; - case SSL_ERROR_WANT_READ: /* these two shouldn't */ - case SSL_ERROR_WANT_WRITE: /* happen (yet) */ - Error - ("FileRead(): Ugh, ok..an SSL_ERROR_WANT_* happened and I didn't think it ever would. Code needs serious work!"); - exit(EX_UNAVAILABLE); - case SSL_ERROR_ZERO_RETURN: - default: - Debug(2, - "FileRead(): performing a SSL_shutdown() on fd %d", - cfp->fd); - SSL_shutdown(cfp->ssl); - Debug(2, - "FileRead(): performing a SSL_free() on fd %d", - cfp->fd); - SSL_free(cfp->ssl); - cfp->ssl = (SSL *) 0; - cfp->ftype = simpleSocket; + case SSL_ERROR_WANT_READ: retval = 0; break; - } - if (sflags != -1) { - Debug(2, - "FileRead(): restoring socket blocking mode on fd %d", - cfp->fd); - fcntl(cfp->fd, F_SETFL, sflags); - } - break; -#endif - default: - retval = 0; - break; - } - - if (retval >= 0) { - Debug(2, "FileRead(): read %d byte%s from fd %d", retval, - (retval == 1) ? "" : "s", cfp->fd); - } else { - Debug(2, "FileRead(): read of %d byte%s from fd %d: %s", len, - (retval == 1) ? "" : "s", cfp->fd, strerror(errno)); - } - return retval; -} - -/* Unless otherwise stated, returns the same values as write(2) */ -int -#if PROTOTYPES -FileWrite(CONSFILE * cfp, const char *buf, int len) -#else -FileWrite(cfp, buf, len) - CONSFILE *cfp; - const char *buf; - int len; -#endif -{ - int len_orig = len; - int len_out = 0; - int retval = 0; -#if HAVE_OPENSSL - /*int r, w; */ - int sflags; -#endif - - if (buf == (char *)0) - return 0; - - if (len < 0) - len = strlen(buf); - - if (len == 0) - return 0; - - switch (cfp->ftype) { - case simpleFile: - case simpleSocket: - while (len > 0) { - if ((retval = write(cfp->fd, buf, len)) < 0) { + case SSL_ERROR_WANT_WRITE: + cfp->waitForWrite = FLAGTRUE; + FD_SET(cfp->fd, &winit); + retval = 0; break; - } - buf += retval; - len -= retval; - len_out += retval; - } - break; -#if HAVE_OPENSSL - case SSLSocket: - /*CheckRW(cfp->fd, &r, &w); */ - sflags = fcntl(cfp->fd, F_GETFL, 0); - if (sflags != -1) { - Debug(2, - "FileWrite(): setting socket to BLOCKING on fd %d", - cfp->fd); - fcntl(cfp->fd, F_SETFL, sflags & ~O_NONBLOCK); - } - while (len > 0) { - retval = SSL_write(cfp->ssl, buf, len); - switch (SSL_get_error(cfp->ssl, retval)) { - case SSL_ERROR_NONE: - break; - case SSL_ERROR_WANT_READ: /* these two shouldn't */ - case SSL_ERROR_WANT_WRITE: /* happen (yet) */ - Error - ("FileWrite(): Ugh, ok..an SSL_ERROR_WANT_* happened and I didn't think it ever would. Code needs serious work!"); - exit(EX_UNAVAILABLE); - case SSL_ERROR_ZERO_RETURN: - default: - Debug(2, - "FileWrite(): performing a SSL_shutdown() on fd %d", - cfp->fd); - SSL_shutdown(cfp->ssl); - Debug(2, - "FileWrite(): performing a SSL_free() on fd %d", - cfp->fd); - SSL_free(cfp->ssl); - cfp->ssl = (SSL *) 0; - cfp->ftype = simpleSocket; - retval = -1; - break; - } - if (retval == -1) { - len_out = -1; + default: + Error("FileRead(): SSL error on fd %d", cfp->fd); + /* fall through */ + case SSL_ERROR_ZERO_RETURN: + retval = -1; + CONDDEBUG((2, + "FileRead(): performing a SSL_shutdown() on fd %d", + cfp->fd)); + SSL_shutdown(cfp->ssl); + CONDDEBUG((2, + "FileRead(): performing a SSL_free() on fd %d", + cfp->fd)); + SSL_free(cfp->ssl); + cfp->ssl = (SSL *)0; + cfp->ftype = simpleSocket; break; - } - buf += retval; - len -= retval; - len_out += retval; - } - if (sflags != -1) { - Debug(2, - "FileWrite(): restoring socket blocking mode on fd %d", - cfp->fd); - fcntl(cfp->fd, F_SETFL, sflags); } break; #endif @@ -1000,45 +960,282 @@ FileWrite(cfp, buf, len) break; } - if (len_out >= 0) { - Debug(2, "FileWrite(): wrote %d byte%s to fd %d", len_out, - (len_out == 1) ? "" : "s", cfp->fd); + if (retval >= 0) { + CONDDEBUG((2, "FileRead(): read %d byte%s from fd %d", retval, + (retval == 1) ? "" : "s", cfp->fd)); + if (fDebug && buf != (char *)0) { + static STRING *tmpString = (STRING *)0; + if (tmpString == (STRING *)0) + tmpString = AllocString(); + BuildString((char *)0, tmpString); + FmtCtlStr(buf, retval > 30 ? 30 : retval, tmpString); + CONDDEBUG((2, "FileRead(): read `%s' from fd %d", + tmpString->string, cfp->fd)); + } } else { - Debug(2, "FileWrite(): write of %d byte%s to fd %d: %s", len_orig, - (len_out == 1) ? "" : "s", cfp->fd, strerror(errno)); + CONDDEBUG((2, + "FileRead(): failed attempted read of %d byte%s from fd %d", + len, (len == 1) ? "" : "s", cfp->fd)); + } + return retval; +} + +/* returns: -1 on error or eof, >= 0 for valid reads */ +int +#if PROTOTYPES +FileWrite(CONSFILE *cfp, char *buf, int len) +#else +FileWrite(cfp, buf, len) + CONSFILE *cfp; + char *buf; + int len; +#endif +{ + int len_orig = len; + int len_out = 0; + int retval = 0; + + if (len < 0 && buf != (char *)0) + len = strlen(buf); + + if (fDebug && len > 0 && buf != (char *)0) { + static STRING *tmpString = (STRING *)0; + if (tmpString == (STRING *)0) + tmpString = AllocString(); + BuildString((char *)0, tmpString); + FmtCtlStr(buf, len > 30 ? 30 : len, tmpString); + CONDDEBUG((2, "FileWrite(): sending `%s' to fd %d", + tmpString->string, cfp->fd)); + } + /* save the data */ + if (len > 0 && buf != (char *)0) + BuildStringN(buf, len, cfp->wbuf); + + /* point at the local data */ + buf = cfp->wbuf->string; + len = cfp->wbuf->used - 1; + + /* if we don't have any, forget it */ + if (buf == (char *)0 || len <= 0) + return 0; + + /* so, we could be blocking or non-blocking. since we may be able + * to block, we'll just keep trying to write while we have data and + * stop when we hit an error or flush all the data. + */ + switch (cfp->ftype) { + case simpleFile: + case simpleSocket: + while (len > 0) { + if ((retval = write(cfp->fd, buf, len)) < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + /* must be non-blocking - so stop */ + retval = 0; + break; + } + retval = -1; + if (errno == EPIPE) + break; + Error("FileWrite(): fd %d: %s", cfp->fd, + strerror(errno)); + break; + } + buf += retval; + len -= retval; + len_out += retval; + } + break; +#if HAVE_OPENSSL + case SSLSocket: + if (cfp->waitForRead == FLAGTRUE) + cfp->waitForRead = FLAGFALSE; + while (len > 0) { + /* in theory, SSL_write always returns 'len' on success + * so the while() loop is a noop. but, just in case i + * read something wrong, we treat SSL_write like write(). + */ + retval = SSL_write(cfp->ssl, buf, len); + switch (SSL_get_error(cfp->ssl, retval)) { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_WANT_READ: + cfp->waitForRead = FLAGTRUE; + retval = len_out = 0; + break; + case SSL_ERROR_WANT_WRITE: + retval = len_out = 0; + break; + default: + Error("FileWrite(): SSL error on fd %d", cfp->fd); + /* fall through */ + case SSL_ERROR_ZERO_RETURN: + retval = -1; + CONDDEBUG((2, + "FileWrite(): performing a SSL_shutdown() on fd %d", + cfp->fd)); + SSL_shutdown(cfp->ssl); + CONDDEBUG((2, + "FileWrite(): performing a SSL_free() on fd %d", + cfp->fd)); + SSL_free(cfp->ssl); + cfp->ssl = (SSL *)0; + cfp->ftype = simpleSocket; + break; + } + if (retval <= 0) + break; + buf += retval; + len -= retval; + len_out += retval; + } + break; +#endif + default: + len_out = -1; + break; + } + + /* so, if we saw an error, just bail...all is done anyway */ + if (retval < 0) + len_out = retval; + + if (len_out > 0) { + /* save the rest for later */ + if (len > 0) { + ShiftString(cfp->wbuf, len_out); + } else { + BuildString((char *)0, cfp->wbuf); + } + } + if (cfp->wbuf->used <= 1) + FD_CLR(cfp->fd, &winit); + else { + FD_SET(cfp->fd, &winit); + CONDDEBUG((2, "FileWrite(): buffered %d byte%s for fd %d", + (cfp->wbuf->used <= 1) ? 0 : cfp->wbuf->used, + (cfp->wbuf->used <= 1) ? "" : "s", cfp->fd)); + } + + if (len_out >= 0) { + CONDDEBUG((2, "FileWrite(): wrote %d byte%s to fd %d", len_out, + (len_out == 1) ? "" : "s", cfp->fd)); + } else { + CONDDEBUG((2, "FileWrite(): write of %d byte%s to fd %d: %s", + len_orig, (len_out == -1) ? "" : "s", cfp->fd, + strerror(errno))); } return len_out; } +int +#if PROTOTYPES +FileCanRead(CONSFILE *cfp, fd_set *prfd, fd_set *pwfd) +#else +FileCanRead(cfp, prfd, pwfd) + CONSFILE *cfp; + fd_set *prfd; + fd_set *pwfd; +#endif +{ + if (cfp == (CONSFILE *)0) + return 0; + + return ((FD_ISSET(cfp->fd, prfd) +#if HAVE_OPENSSL + && cfp->waitForRead != FLAGTRUE) || (FD_ISSET(cfp->fd, pwfd) + && cfp->waitForWrite == + FLAGTRUE +#endif + )); +} + +int +#if PROTOTYPES +FileCanWrite(CONSFILE *cfp, fd_set *prfd, fd_set *pwfd) +#else +FileCanWrite(cfp, prfd, pwfd) + CONSFILE *cfp; + fd_set *prfd; + fd_set *pwfd; +#endif +{ + if (cfp == (CONSFILE *)0) + return 0; + + return ((FD_ISSET(cfp->fd, pwfd) +#if HAVE_OPENSSL + && cfp->waitForWrite != FLAGTRUE) || (FD_ISSET(cfp->fd, prfd) + && cfp->waitForRead == + FLAGTRUE +#endif + )); +} + +int +#if PROTOTYPES +FileBufEmpty(CONSFILE *cfp) +#else +FileBufEmpty(cfp) + CONSFILE *cfp; +#endif +{ + if (cfp == (CONSFILE *)0) + return 1; + return (cfp->wbuf->used <= 1); +} + void #if PROTOTYPES -FileVWrite(CONSFILE * cfp, const char *fmt, va_list ap) +VWrite(CONSFILE *cfp, STRING *str, unsigned which, char *fmt, va_list ap) #else -FileVWrite(cfp, fmt, ap) +VWrite(cfp, str, which, fmt, ap) CONSFILE *cfp; - const char *fmt; + STRING *str; + unsigned which; + char *fmt; va_list ap; #endif { int s, l, e; char c; - static STRING *msg = (STRING *) 0; + static STRING *msg = (STRING *)0; static short flong, fneg; if (fmt == (char *)0) return; + switch (which) { + case 0: + if (cfp == (CONSFILE *)0) + return; + break; + case 1: + if (str == (STRING *)0) + return; + BuildString((char *)0, str); + break; + default: + return; + } - if (msg == (STRING *) 0) + if (msg == (STRING *)0) msg = AllocString(); fneg = flong = 0; for (e = s = l = 0; (c = fmt[s + l]) != '\000'; l++) { if (c == '%') { if (e) { e = 0; - FileWrite(cfp, "%", 1); + if (which == 0) + FileWrite(cfp, "%", 1); + else if (which == 1) + BuildStringChar('%', str); } else { e = 1; - FileWrite(cfp, fmt + s, l); + if (which == 0) + FileWrite(cfp, fmt + s, l); + else if (which == 1) + BuildStringN(fmt + s, l, str); s += l; l = 0; } @@ -1058,11 +1255,17 @@ FileVWrite(cfp, fmt, ap) continue; case 'c': cc = (char)va_arg(ap, int); - FileWrite(cfp, &cc, 1); + if (which == 0) + FileWrite(cfp, &cc, 1); + else if (which == 1) + BuildStringChar(cc, str); break; case 's': p = va_arg(ap, char *); - FileWrite(cfp, p, -1); + if (which == 0) + FileWrite(cfp, p, -1); + else if (which == 1) + BuildString(p, str); break; case 'd': i = (flong ? va_arg(ap, long) : (long)va_arg(ap, int)); @@ -1093,14 +1296,20 @@ FileVWrite(cfp, fmt, ap) msg->string[u - i - 1] = temp; } if (fneg) { - FileWrite(cfp, "-", 1); + if (which == 0) + FileWrite(cfp, "-", 1); + else if (which == 1) + BuildStringChar('-', str); fneg = 0; } - FileWrite(cfp, msg->string, msg->used - 1); + if (which == 0) + FileWrite(cfp, msg->string, msg->used - 1); + else if (which == 1) + BuildString(msg->string, str); break; default: Error - ("FileVWrite(): unknown conversion character `%c' in `%s'", + ("VWrite(): unknown conversion character `%c' in `%s'", c, fmt); break; } @@ -1109,17 +1318,58 @@ FileVWrite(cfp, fmt, ap) e = flong = 0; } } - if (l) - FileWrite(cfp, fmt + s, l); + if (l) { + if (which == 0) + FileWrite(cfp, fmt + s, l); + else if (which == 1) + BuildStringN(fmt + s, l, str); + } +} + +char * +#if PROTOTYPES +BuildStringPrint(STRING *str, char *fmt, ...) +#else +BuildStringPrint(str, fmt, va_alist) + STRING *str; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if PROTOTYPES + va_start(ap, fmt); +#else + va_start(ap); +#endif + VWrite((CONSFILE *)0, str, 1, fmt, ap); + va_end(ap); + if (str == (STRING *)0) + return (char *)0; + else + return str->string; } void #if PROTOTYPES -FilePrint(CONSFILE * cfp, const char *fmt, ...) +FileVWrite(CONSFILE *cfp, char *fmt, va_list ap) +#else +FileVWrite(cfp, fmt, ap) + CONSFILE *cfp; + char *fmt; + va_list ap; +#endif +{ + VWrite(cfp, (STRING *)0, 0, fmt, ap); +} + +void +#if PROTOTYPES +FilePrint(CONSFILE *cfp, char *fmt, ...) #else FilePrint(cfp, fmt, va_alist) CONSFILE *cfp; - const char *fmt; + char *fmt; va_dcl #endif { @@ -1136,7 +1386,7 @@ FilePrint(cfp, fmt, va_alist) /* Unless otherwise stated, returns the same values as fstat(2) */ int #if PROTOTYPES -FileStat(CONSFILE * cfp, struct stat *buf) +FileStat(CONSFILE *cfp, struct stat *buf) #else FileStat(cfp, buf) CONSFILE *cfp; @@ -1168,7 +1418,7 @@ FileStat(cfp, buf) /* Unless otherwise stated, returns the same values as lseek(2) */ int #if PROTOTYPES -FileSeek(CONSFILE * cfp, off_t offset, int whence) +FileSeek(CONSFILE *cfp, off_t offset, int whence) #else FileSeek(cfp, offset, whence) CONSFILE *cfp; @@ -1201,7 +1451,7 @@ FileSeek(cfp, offset, whence) /* Returns the file descriptor number of the underlying file */ int #if PROTOTYPES -FileFDNum(CONSFILE * cfp) +FileFDNum(CONSFILE *cfp) #else FileFDNum(cfp) CONSFILE *cfp; @@ -1209,6 +1459,9 @@ FileFDNum(cfp) { int retval = 0; + if (cfp == (CONSFILE *)0) + return -1; + switch (cfp->ftype) { case simpleFile: retval = cfp->fd; @@ -1232,7 +1485,7 @@ FileFDNum(cfp) /* Returns the file type */ enum consFileType #if PROTOTYPES -FileGetType(CONSFILE * cfp) +FileGetType(CONSFILE *cfp) #else FileGetType(cfp) CONSFILE *cfp; @@ -1255,7 +1508,7 @@ FileGetType(cfp) /* Sets the file type */ void #if PROTOTYPES -FileSetType(CONSFILE * cfp, enum consFileType type) +FileSetType(CONSFILE *cfp, enum consFileType type) #else FileSetType(cfp, type) CONSFILE *cfp; @@ -1269,7 +1522,7 @@ FileSetType(cfp, type) /* Get the SSL instance */ SSL * #if PROTOTYPES -FileGetSSL(CONSFILE * cfp) +FileGetSSL(CONSFILE *cfp) #else FileGetSSL(cfp) CONSFILE *cfp; @@ -1281,7 +1534,7 @@ FileGetSSL(cfp) /* Sets the SSL instance */ void #if PROTOTYPES -FileSetSSL(CONSFILE * cfp, SSL * ssl) +FileSetSSL(CONSFILE *cfp, SSL *ssl) #else FileSetSSL(cfp, ssl) CONSFILE *cfp; @@ -1290,12 +1543,78 @@ FileSetSSL(cfp, ssl) { cfp->ssl = ssl; } + +/* return -1 on error, 0 for "wait" state, 1 for success */ +int +#if PROTOTYPES +FileCanSSLAccept(CONSFILE *cfp, fd_set *prfd, fd_set *pwfd) +#else +FileCanSSLAccept(cfp) + CONSFILE *cfp; + fd_set *prfd; + fd_set *pwfd; +#endif +{ + if (cfp == (CONSFILE *)0) + return 0; + + return ((FD_ISSET(cfp->fd, prfd) && cfp->waitForRead == FLAGTRUE) || + (FD_ISSET(cfp->fd, pwfd) && cfp->waitForWrite == FLAGTRUE) || + (cfp->waitForRead != FLAGTRUE && + cfp->waitForWrite != FLAGTRUE)); +} + +/* return -1 on error, 0 for "wait" state, 1 for success */ +int +#if PROTOTYPES +FileSSLAccept(CONSFILE *cfp) +#else +FileSSLAccept(cfp) + CONSFILE *cfp; +#endif +{ + int retval; + if (cfp->waitForWrite == FLAGTRUE) { + cfp->waitForWrite = FLAGFALSE; + if (cfp->wbuf->used <= 1) + FD_CLR(cfp->fd, &winit); + } + cfp->waitForRead = FLAGFALSE; + + CONDDEBUG((1, "FileSSLAccept(): about to SSL_accept() for fd %d", + cfp->fd)); + retval = SSL_accept(cfp->ssl); + switch (SSL_get_error(cfp->ssl, retval)) { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_WANT_READ: + cfp->waitForRead = FLAGTRUE; + return 0; + case SSL_ERROR_WANT_WRITE: + cfp->waitForWrite = FLAGTRUE; + FD_SET(cfp->fd, &winit); + return 0; + default: + Error("FileSSLAccept(): SSL error on fd %d", cfp->fd); + /* fall through */ + case SSL_ERROR_ZERO_RETURN: + SSL_free(cfp->ssl); + cfp->ssl = (SSL *)0; + cfp->ftype = simpleSocket; + return -1; + } + cfp->ftype = SSLSocket; + CONDDEBUG((1, "FileSSLAccept(): SSL Connection: %s :: %s", + SSL_get_cipher_version(cfp->ssl), + SSL_get_cipher_name(cfp->ssl))); + return 1; +} #endif /* Unless otherwise stated, returns the same values as send(2) */ int #if PROTOTYPES -FileSend(CONSFILE * cfp, const void *msg, size_t len, int flags) +FileSend(CONSFILE *cfp, const void *msg, size_t len, int flags) #else FileSend(cfp, msg, len, flags) CONSFILE *cfp; @@ -1326,11 +1645,120 @@ FileSend(cfp, msg, len, flags) return retval; } +/* replace trailing space with '\000' in a string and return + * a pointer to the start of the non-space part + */ +char * +#if PROTOTYPES +PruneSpace(char *string) +#else +PruneSpace(string) + char *string; +#endif +{ + char *p; + char *head = (char *)0; + char *tail = (char *)0; + + /* Don't do much if it's crap */ + if (string == (char *)0 || *string == '\000') + return string; + + /* Now for the tricky part - search the string */ + for (p = string; *p != '\000'; p++) { + if (isspace((int)(*p))) { + if (tail == (char *)0) + tail = p; /* possible end of string */ + } else { + if (head == (char *)0) + head = p; /* found the start */ + tail = (char *)0; /* reset tail */ + } + } + + if (tail != (char *)0) + *tail = '\000'; + + if (head != (char *)0) + return head; + else + return string; +} + +int +#if PROTOTYPES +IsMe(char *id) +#else +IsMe(id) + char *id; +#endif +{ + int j, i; + struct hostent *he; + in_addr_t addr; +#if HAVE_INET_ATON + struct in_addr inetaddr; +#endif + + /* check for ip address match */ +#if HAVE_INET_ATON + if (inet_aton(id, &inetaddr) != 0) { + addr = inetaddr.s_addr; +#else + addr = inet_addr(id); + if (addr != (in_addr_t) (-1)) { +#endif + for (i = 0; + myAddrs != (struct in_addr *)0 && + myAddrs[i].s_addr != (in_addr_t) 0; i++) { + if ( +#if HAVE_MEMCMP + memcmp(&(myAddrs[i].s_addr), &addr, sizeof(addr)) +#else + bcmp(&(myAddrs[i].s_addr), &addr, sizeof(addr)) +#endif + == 0) + return 1; + } + return 0; + } + + /* check for ip match of hostname */ + if ((struct hostent *)0 == (he = gethostbyname(id))) { + Error("IsMe(): gethostbyname(%s): %s", id, hstrerror(h_errno)); + return 0; + } + if (4 != he->h_length || AF_INET != he->h_addrtype) { + Error + ("IsMe(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)", + id, he->h_length, AF_INET, he->h_addrtype); + return 0; + } + + for (j = 0; he->h_addr_list[j] != (char *)0; j++) { + for (i = 0; + myAddrs != (struct in_addr *)0 && + myAddrs[i].s_addr != (in_addr_t) 0; i++) { + if ( +#if HAVE_MEMCMP + memcmp(&(myAddrs[i].s_addr), he->h_addr_list[j], + he->h_length) +#else + bcmp(&(myAddrs[i].s_addr), he->h_addr_list[j], + he->h_length) +#endif + == 0) + return 1; + } + } + return 0; +} + #if HAVE_OPENSSL /* Unless otherwise stated, returns the same values as send(2) */ int #if PROTOTYPES -SSLVerifyCallback(int ok, X509_STORE_CTX * store) +SSLVerifyCallback(int ok, X509_STORE_CTX *store) #else SSLVerifyCallback(ok, store) int ok; @@ -1343,13 +1771,13 @@ SSLVerifyCallback(ok, store) X509 *cert = X509_STORE_CTX_get_current_cert(store); int depth = X509_STORE_CTX_get_error_depth(store); - Debug(1, - "SSLVerifyCallback(): info of certificate at depth: %d", - depth); + CONDDEBUG((1, + "SSLVerifyCallback(): info of certificate at depth: %d", + depth)); X509_NAME_oneline(X509_get_issuer_name(cert), data, 256); - Debug(1, "SSLVerifyCallback(): issuer = %s", data); + CONDDEBUG((1, "SSLVerifyCallback(): issuer = %s", data)); X509_NAME_oneline(X509_get_subject_name(cert), data, 256); - Debug(1, "SSLVerifyCallback(): subject = %s", data); + CONDDEBUG((1, "SSLVerifyCallback(): subject = %s", data)); } } else { X509 *cert = X509_STORE_CTX_get_current_cert(store); @@ -1368,3 +1796,28 @@ SSLVerifyCallback(ok, store) return ok; } #endif + +int +#if PROTOTYPES +SetFlags(int fd, int s, int c) +#else +SetFlags(fd, s, c) + int fd, s, c; +#endif +{ + int flags; + + if ((flags = fcntl(fd, F_GETFL)) >= 0) { + flags |= s; + flags &= ~c; + if (fcntl(fd, F_SETFL, flags) < 0) { + Error("SetFlags(): fcntl(%u,F_SETFL): %s", fd, + strerror(errno)); + return 0; + } + } else { + Error("SetFlags(): fcntl(%u,F_GETFL): %s", fd, strerror(errno)); + return 0; + } + return 1; +} diff --git a/conserver/util.h b/conserver/util.h index 00f49bf..cc7b902 100644 --- a/conserver/util.h +++ b/conserver/util.h @@ -1,5 +1,5 @@ /* - * $Id: util.h,v 1.41 2003-03-08 08:39:57-08 bryan Exp $ + * $Id: util.h,v 1.52 2003-08-23 11:06:35-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -34,6 +34,24 @@ enum consFileType { nothing }; +typedef enum IOState { + ISDISCONNECTED = 0, + INCONNECT, + ISNORMAL, +#if HAVE_OPENSSL + INSSLACCEPT, + INSSLSHUTDOWN, +#endif + ISFLUSHING +} IOSTATE; + +typedef enum flag { + FLAGUNKNOWN = 0, + FLAGTRUE, + FLAGFALSE +} FLAG; + + typedef struct dynamicString { char *string; int used; @@ -46,18 +64,27 @@ typedef struct consFile { /* Standard socket type stuff */ enum consFileType ftype; int fd; + STRING *wbuf; #if HAVE_OPENSSL /* SSL stuff */ SSL *ssl; - int waitonWrite; - int waitonRead; + FLAG waitForWrite; + FLAG waitForRead; #endif /* Add crypto stuff to suit */ } CONSFILE; -extern int isMultiProc, fDebug, fVerbose; +extern int isMultiProc, fDebug, fVerbose, fErrorPrinted; extern char *progname; extern pid_t thepid; +#define MAXHOSTNAME 1024 +extern char myHostname[]; +extern struct in_addr *myAddrs; +extern fd_set rinit; +extern fd_set winit; +extern int maxfd; +extern int debugLineNo; +extern char *debugFileName; extern const char *StrTime PARAMS((time_t *)); extern void Debug PARAMS((int, char *, ...)); @@ -72,9 +99,9 @@ extern CONSFILE *FileOpenFD PARAMS((int, enum consFileType)); extern CONSFILE *FileOpen PARAMS((const char *, int, int)); extern int FileClose PARAMS((CONSFILE **)); extern int FileRead PARAMS((CONSFILE *, void *, int)); -extern int FileWrite PARAMS((CONSFILE *, const char *, int)); -extern void FileVWrite PARAMS((CONSFILE *, const char *, va_list)); -extern void FilePrint PARAMS((CONSFILE *, const char *, ...)); +extern int FileWrite PARAMS((CONSFILE *, char *, int)); +extern void FileVWrite PARAMS((CONSFILE *, char *, va_list)); +extern void FilePrint PARAMS((CONSFILE *, char *, ...)); extern int FileStat PARAMS((CONSFILE *, struct stat *)); extern int FileSeek PARAMS((CONSFILE *, off_t, int)); extern int FileSend PARAMS((CONSFILE *, const void *, size_t, int)); @@ -85,6 +112,9 @@ extern char *BuildTmpString PARAMS((const char *)); extern char *BuildTmpStringChar PARAMS((const char)); extern char *BuildString PARAMS((const char *, STRING *)); extern char *BuildStringChar PARAMS((const char, STRING *)); +extern char *BuildStringPrint PARAMS((STRING *, char *, ...)); +extern char *BuildStringN PARAMS((const char *, int, STRING *)); +extern char *ShiftString PARAMS((STRING *, int)); extern void InitString PARAMS((STRING *)); extern void DestroyString PARAMS((STRING *)); extern void DestroyStrings PARAMS((void)); @@ -94,8 +124,16 @@ extern enum consFileType FileGetType PARAMS((CONSFILE *)); extern void FileSetType PARAMS((CONSFILE *, enum consFileType)); extern void Bye PARAMS((int)); extern void DestroyDataStructures PARAMS((void)); +extern int IsMe PARAMS((char *)); +extern char *PruneSpace PARAMS((char *)); +extern int FileCanRead PARAMS((CONSFILE *, fd_set *, fd_set *)); +extern int FileCanWrite PARAMS((CONSFILE *, fd_set *, fd_set *)); +extern int FileBufEmpty PARAMS((CONSFILE *)); +extern int SetFlags PARAMS((int, int, int)); #if HAVE_OPENSSL extern SSL *FileGetSSL PARAMS((CONSFILE *)); extern void FileSetSSL PARAMS((CONSFILE *, SSL *)); extern int SSLVerifyCallback PARAMS((int, X509_STORE_CTX *)); +extern int FileSSLAccept PARAMS((CONSFILE *)); +extern int FileCanSSLAccept PARAMS((CONSFILE *, fd_set *, fd_set *)); #endif diff --git a/conserver/version.h b/conserver/version.h index 9e07784..5b2f20f 100644 --- a/conserver/version.h +++ b/conserver/version.h @@ -1,5 +1,5 @@ /* - * $Id: version.h,v 1.42 2003-04-08 16:19:19-07 bryan Exp $ + * $Id: version.h,v 1.46 2003-09-22 10:41:28-07 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 7.2.7" +#define THIS_VERSION "conserver.com version 8.0.0" diff --git a/console/Makefile.in b/console/Makefile.in index 31d6e28..fa5fbea 100644 --- a/console/Makefile.in +++ b/console/Makefile.in @@ -25,7 +25,7 @@ LIBS = @LIBS@ ### Makefile rules - no user-servicable parts below -CONSOLE_OBJS = console.o ../conserver/util.o +CONSOLE_OBJS = console.o getpassword.o ../conserver/util.o CONSOLE_HDRS = ../config.h $(top_srcdir)/compat.h $(top_srcdir)/conserver/port.h ALL = console diff --git a/console/console.c b/console/console.c index 0ed773b..4710042 100644 --- a/console/console.c +++ b/console/console.c @@ -1,5 +1,5 @@ /* - * $Id: console.c,v 5.117 2003-04-06 05:29:24-07 bryan Exp $ + * $Id: console.c,v 5.137 2003-09-22 08:23:57-07 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -27,25 +27,13 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include + +#include + +#include #include - #include - #if HAVE_OPENSSL #include #include @@ -53,7 +41,7 @@ #endif -int fReplay = 0, fRaw = 0, fVersion = 0, fStrip = 0; +int fReplay = 0, fVersion = 0, fStrip = 0; #if HAVE_OPENSSL int fReqEncryption = 1; char *pcCredFile = (char *)0; @@ -64,11 +52,13 @@ char *pcInMaster = /* which machine is current */ char *pcPort = DEFPORT; unsigned short bindPort; CONSFILE *cfstdout; +char *pcUser = (char *)0; +int disconnectCount = 0; static char acMesg[8192]; /* the buffer for startup negotiation */ #if HAVE_OPENSSL -SSL_CTX *ctx = (SSL_CTX *) 0; +SSL_CTX *ctx = (SSL_CTX *)0; void #if PROTOTYPES @@ -77,13 +67,13 @@ SetupSSL(void) SetupSSL() #endif { - if (ctx == (SSL_CTX *) 0) { + if (ctx == (SSL_CTX *)0) { SSL_load_error_strings(); if (!SSL_library_init()) { Error("SSL library initialization failed"); exit(EX_UNAVAILABLE); } - if ((ctx = SSL_CTX_new(SSLv23_method())) == (SSL_CTX *) 0) { + if ((ctx = SSL_CTX_new(SSLv23_method())) == (SSL_CTX *)0) { Error("Creating SSL context failed"); exit(EX_UNAVAILABLE); } @@ -121,7 +111,7 @@ SetupSSL() void #if PROTOTYPES -AttemptSSL(CONSFILE * pcf) +AttemptSSL(CONSFILE *pcf) #else AttemptSSL(pcf) CONSFILE *pcf; @@ -129,7 +119,7 @@ AttemptSSL(pcf) { SSL *ssl; - if (ctx == (SSL_CTX *) 0) { + if (ctx == (SSL_CTX *)0) { Error("WTF? The SSL context disappeared?!?!?"); exit(EX_UNAVAILABLE); } @@ -139,16 +129,15 @@ AttemptSSL(pcf) } FileSetSSL(pcf, ssl); SSL_set_fd(ssl, FileFDNum(pcf)); - Debug(1, "About to SSL_connect() on fd %d", FileFDNum(pcf)); + CONDDEBUG((1, "About to SSL_connect() on fd %d", FileFDNum(pcf))); if (SSL_connect(ssl) <= 0) { Error("SSL negotiation failed"); ERR_print_errors_fp(stderr); exit(EX_UNAVAILABLE); } FileSetType(pcf, SSLSocket); - if (fDebug) - Debug(1, "SSL Connection: %s :: %s", SSL_get_cipher_version(ssl), - SSL_get_cipher_name(ssl)); + CONDDEBUG((1, "SSL Connection: %s :: %s", SSL_get_cipher_version(ssl), + SSL_get_cipher_name(ssl))); } #endif @@ -165,7 +154,7 @@ DestroyDataStructures() */ static void #if PROTOTYPES -PutCtlc(int c, FILE * fp) +PutCtlc(int c, FILE *fp) #else PutCtlc(c, fp) int c; @@ -208,6 +197,7 @@ Usage(wantfull) #else "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", #if HAVE_OPENSSL @@ -216,7 +206,6 @@ Usage(wantfull) "E ignored - encryption not compiled into code", #endif "f(F) force read/write connection (and replay)", - "G connect to the console group only", "i(I) display information in machine-parseable form (on master)", "h output this message", "l user use username instead of current username", @@ -226,6 +215,7 @@ Usage(wantfull) "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", "v be more verbose", "V show version information", @@ -235,12 +225,12 @@ Usage(wantfull) }; fprintf(stderr, - "%s: usage [-aAEfFGsS] [-7Dv] [-c cred] [-M mach] [-p port] [-e esc] [-l username] console\n", + "usage: %s [-aAEfFsS] [-7Dv] [-c cred] [-M mach] [-p port] [-e esc] [-l username] console\n", progname); fprintf(stderr, - "%s: usage [-hiIPrRuVwWx] [-7Dv] [-M mach] [-p port] [-[bB] message]\n", + "usage: %s [-hiIPrRuVwWx] [-7Dv] [-M mach] [-p port] [-d [user][@console]] [-[bB] message] [-t [user][@console] message]\n", progname); - fprintf(stderr, "%s: usage [-qQ] [-7Dv] [-M mach] [-p port]\n", + fprintf(stderr, "usage: %s [-qQ] [-7Dv] [-M mach] [-p port]\n", progname); if (wantfull) { @@ -260,8 +250,8 @@ Version() #endif { int i; - static STRING *acA1 = (STRING *) 0; - static STRING *acA2 = (STRING *) 0; + static STRING *acA1 = (STRING *)0; + static STRING *acA2 = (STRING *)0; char *optionlist[] = { #if HAVE_DMALLOC "dmalloc", @@ -274,41 +264,21 @@ Version() #endif #if HAVE_PAM "pam", -#endif -#if HAVE_POSIX_REGCOMP - "regex", #endif (char *)0 }; - if (acA1 == (STRING *) 0) + if (acA1 == (STRING *)0) acA1 = AllocString(); - if (acA2 == (STRING *) 0) + if (acA2 == (STRING *)0) acA2 = AllocString(); Msg("%s", THIS_VERSION); - Msg("initial master server `%s\'", pcInMaster); + Msg("default initial master server `%s\'", MASTERHOST); Msg("default escape sequence `%s%s\'", FmtCtl(DEFATTN, acA1), FmtCtl(DEFESC, acA2)); - /* Look for non-numeric characters */ - for (i = 0; pcPort[i] != '\000'; i++) - if (!isdigit((int)pcPort[i])) - break; + Msg("default port referenced as `%s'", DEFPORT); - if (pcPort[i] == '\000') { - /* numeric only */ - bindPort = atoi(pcPort); - Msg("on port %hu (referenced as `%s')", bindPort, pcPort); - } else { - /* non-numeric only */ - struct servent *pSE; - if ((struct servent *)0 == (pSE = getservbyname(pcPort, "tcp"))) { - Error("getservbyname(%s): %s", pcPort, strerror(errno)); - } else { - bindPort = ntohs((u_short) pSE->s_port); - Msg("on port %hu (referenced as `%s')", bindPort, pcPort); - } - } BuildString((char *)0, acA1); if (optionlist[0] == (char *)0) BuildString("none", acA1); @@ -456,50 +426,56 @@ ParseEsc(pcText) */ CONSFILE * #if PROTOTYPES -GetPort(char *pcToHost, struct sockaddr_in *pPort, unsigned short sPort) +GetPort(char *pcToHost, unsigned short sPort) #else -GetPort(pcToHost, pPort, sPort) +GetPort(pcToHost, sPort) char *pcToHost; - struct sockaddr_in *pPort; unsigned short sPort; #endif { int s; struct hostent *hp = (struct hostent *)0; + struct sockaddr_in port; #if HAVE_MEMSET - memset((void *)pPort, '\000', sizeof(*pPort)); + memset((void *)(&port), '\000', sizeof(port)); #else - bzero((char *)pPort, sizeof(*pPort)); + bzero((char *)(&port), sizeof(port)); #endif - pPort->sin_addr.s_addr = inet_addr(pcToHost); - if ((in_addr_t) (-1) == pPort->sin_addr.s_addr) { +#if HAVE_INET_ATON + if (inet_aton(pcToHost, &(port.sin_addr)) == 0) +#else + port.sin_addr.s_addr = inet_addr(pcToHost); + if ((in_addr_t) (-1) == port.sin_addr.s_addr) +#endif + { if ((struct hostent *)0 != (hp = gethostbyname(pcToHost))) { #if HAVE_MEMCPY - memcpy((char *)&pPort->sin_addr.s_addr, (char *)hp->h_addr, + memcpy((char *)&port.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); #else - bcopy((char *)hp->h_addr, (char *)&pPort->sin_addr.s_addr, + bcopy((char *)hp->h_addr, (char *)&port.sin_addr.s_addr, hp->h_length); #endif } else { Error("gethostbyname(%s): %s", pcToHost, hstrerror(h_errno)); - exit(EX_UNAVAILABLE); + return (CONSFILE *)0; } } - pPort->sin_port = sPort; - pPort->sin_family = AF_INET; + port.sin_port = sPort; + port.sin_family = AF_INET; if (fDebug) { - if ((struct hostent *)0 != hp && (char *)0 != hp->h_name) - Debug(1, "GetPort: hostname=%s (%s), ip=%s, port=%hu", - hp->h_name, pcToHost, inet_ntoa(pPort->sin_addr), - ntohs(sPort)); - else - Debug(1, - "GetPort: hostname= (%s), ip=%s, port=%hu", - pcToHost, inet_ntoa(pPort->sin_addr), ntohs(sPort)); + if ((struct hostent *)0 != hp && (char *)0 != hp->h_name) { + CONDDEBUG((1, "GetPort: hostname=%s (%s), ip=%s, port=%hu", + hp->h_name, pcToHost, inet_ntoa(port.sin_addr), + ntohs(sPort))); + } else { + CONDDEBUG((1, + "GetPort: hostname= (%s), ip=%s, port=%hu", + pcToHost, inet_ntoa(port.sin_addr), ntohs(sPort))); + } } /* set up the socket to talk to the server for all consoles @@ -507,12 +483,12 @@ GetPort(pcToHost, pPort, sPort) */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { Error("socket(AF_INET,SOCK_STREAM): %s", strerror(errno)); - exit(EX_UNAVAILABLE); + return (CONSFILE *)0; } - if (connect(s, (struct sockaddr *)pPort, sizeof(*pPort)) < 0) { - Error("connect(): %hu@%s: %s", ntohs(pPort->sin_port), pcToHost, + if (connect(s, (struct sockaddr *)(&port), sizeof(port)) < 0) { + Error("connect(): %hu@%s: %s", ntohs(port.sin_port), pcToHost, strerror(errno)); - exit(EX_UNAVAILABLE); + return (CONSFILE *)0; } return FileOpenFD(s, simpleSocket); @@ -523,17 +499,7 @@ GetPort(pcToHost, pPort, sPort) * correct mode for us to do our thing */ static int screwy = 0; -#if HAVE_TERMIOS_H static struct termios o_tios; -#else -# if HAVE_TERMIO_H -static struct termio o_tio; -# else -static struct sgttyb o_sty; -static struct tchars o_tchars; -static struct ltchars o_ltchars; -# endif -#endif /* @@ -548,111 +514,25 @@ C2Raw() C2Raw() #endif { -#if HAVE_TERMIOS_H struct termios n_tios; -#else -# if HAVE_TERMIO_H - struct termio n_tio; -# else - struct sgttyb n_sty; - struct tchars n_tchars; - struct ltchars n_ltchars; -# endif -#endif if (!isatty(0) || 0 != screwy) return; -#if HAVE_TERMIOS_H -# if HAVE_TCGETATTR if (0 != tcgetattr(0, &o_tios)) { Error("tcgetattr(0): %s", strerror(errno)); exit(EX_UNAVAILABLE); } -# else - if (0 != ioctl(0, TCGETS, &o_tios)) { - Error("iotcl(0, TCGETS): %s", strerror(errno)); - exit(EX_UNAVAILABLE); - } -# endif n_tios = o_tios; n_tios.c_iflag &= ~(INLCR | IGNCR | ICRNL | IUCLC | IXON); n_tios.c_oflag &= ~OPOST; n_tios.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN); n_tios.c_cc[VMIN] = 1; n_tios.c_cc[VTIME] = 0; -# if HAVE_TCSETATTR if (0 != tcsetattr(0, TCSANOW, &n_tios)) { Error("tcsetattr(0, TCSANOW): %s", strerror(errno)); exit(EX_UNAVAILABLE); } -# else - if (0 != ioctl(0, TCSETS, &n_tios)) { - Error("ioctl(0, TCSETS): %s", strerror(errno)); - exit(EX_UNAVAILABLE); - } -# endif -#else -# if HAVE_TERMIO_H - if (0 != ioctl(0, TCGETA, &o_tio)) { - Error("iotcl(0, TCGETA): %s", strerror(errno)); - exit(EX_UNAVAILABLE); - } - n_tio = o_tio; - n_tio.c_iflag &= ~(INLCR | IGNCR | ICRNL | IUCLC | IXON); - n_tio.c_oflag &= ~OPOST; - n_tio.c_lflag &= - ~(ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); - n_tio.c_cc[VMIN] = 1; - n_tio.c_cc[VTIME] = 0; - if (0 != ioctl(0, TCSETAF, &n_tio)) { - Error("iotcl(0, TCSETAF): %s", strerror(errno)); - exit(EX_UNAVAILABLE); - } -# else - if (0 != ioctl(0, TIOCGETP, (char *)&o_sty)) { - Error("iotcl(0, TIOCGETP): %s", strerror(errno)); - exit(EX_UNAVAILABLE); - } - n_sty = o_sty; - - n_sty.sg_flags |= CBREAK; - n_sty.sg_flags &= ~(CRMOD | ECHO); - n_sty.sg_kill = -1; - n_sty.sg_erase = -1; - if (0 != ioctl(0, TIOCSETP, (char *)&n_sty)) { - Error("iotcl(0, TIOCSETP): %s", strerror(errno)); - exit(EX_UNAVAILABLE); - } - - /* stty undef all tty chars - */ - if (-1 == ioctl(0, TIOCGETC, (char *)&n_tchars)) { - Error("ioctl(0, TIOCGETC): %s", strerror(errno)); - return; - } - o_tchars = n_tchars; - n_tchars.t_intrc = -1; - n_tchars.t_quitc = -1; - if (-1 == ioctl(0, TIOCSETC, (char *)&n_tchars)) { - Error("ioctl(0, TIOCSETC): %s", strerror(errno)); - return; - } - if (-1 == ioctl(0, TIOCGLTC, (char *)&n_ltchars)) { - Error("ioctl(0, TIOCGLTC): %s", strerror(errno)); - return; - } - o_ltchars = n_ltchars; - n_ltchars.t_suspc = -1; - n_ltchars.t_dsuspc = -1; - n_ltchars.t_flushc = -1; - n_ltchars.t_lnextc = -1; - if (-1 == ioctl(0, TIOCSLTC, (char *)&n_ltchars)) { - Error("ioctl(0, TIOCSLTC): %s", strerror(errno)); - return; - } -# endif -#endif screwy = 1; } @@ -668,201 +548,60 @@ C2Cooked() { if (!screwy) return; -#if HAVE_TERMIOS_H -# if HAVE_TCSETATTR tcsetattr(0, TCSANOW, &o_tios); -# else - ioctl(0, TCSETS, (char *)&o_tios); -# endif -#else -# if HAVE_TERMIO_H - ioctl(0, TCSETA, (char *)&o_tio); -# else - ioctl(0, TIOCSETP, (char *)&o_sty); - ioctl(0, TIOCSETC, (char *)&o_tchars); - ioctl(0, TIOCSLTC, (char *)&o_ltchars); -# endif -#endif screwy = 0; } - - -/* send out some data along the connection (ksb) - */ -static void +char * #if PROTOTYPES -SendOut(CONSFILE * fd, char *pcBuf, int iLen) +ReadReply(CONSFILE *fd, int toEOF) #else -SendOut(fd, pcBuf, iLen) +ReadReply(fd) CONSFILE *fd; - int iLen; - char *pcBuf; + int toEOF; #endif { int nr; + static char buf[1024]; + static STRING *result = (STRING *)0; - if (fDebug) { - static STRING *tmpString = (STRING *) 0; - if (tmpString == (STRING *) 0) - tmpString = AllocString(); - BuildString((char *)0, tmpString); - FmtCtlStr(pcBuf, iLen, tmpString); - Debug(1, "SendOut: `%s'", tmpString->string); - } - while (0 != iLen) { - if (-1 == (nr = FileWrite(fd, pcBuf, iLen))) { - C2Cooked(); - Error("lost connection"); - exit(EX_UNAVAILABLE); - } - iLen -= nr; - pcBuf += nr; - } -} + if (result == (STRING *)0) + result = AllocString(); + else + BuildString((char *)0, result); -/* read a reply from the console server (ksb) - * if pcWnat == (char *)0 we strip \r\n from the end and return strlen - */ -static int -#if PROTOTYPES -ReadReply(CONSFILE * fd, char *pcBuf, int iLen, char *pcWant) -#else -ReadReply(fd, pcBuf, iLen, pcWant) - CONSFILE *fd; - int iLen; - char *pcBuf, *pcWant; -#endif -{ - int nr, j, iKeep; - - iKeep = iLen; - for (j = 0; j < iLen; /* j+=nr */ ) { - switch (nr = FileRead(fd, &pcBuf[j], iLen - 1)) { + while (1) { + switch (nr = FileRead(fd, buf, sizeof(buf))) { case 0: - if (iKeep != iLen) { - break; - } /* fall through */ case -1: + if (result->used > 1 || toEOF) + break; C2Cooked(); Error("lost connection"); exit(EX_UNAVAILABLE); default: - j += nr; - iLen -= nr; - if ('\n' == pcBuf[j - 1]) { - pcBuf[j] = '\000'; + BuildStringN(buf, nr, result); + if (toEOF) /* if toEOF, read until EOF */ + continue; + if ((result->used > 1) && + (result->string[result->used - 2] == '\n')) break; - } - if (0 == iLen) { - C2Cooked(); - Error("reply too long"); - exit(EX_UNAVAILABLE); - } continue; } break; } - /* in this case the called wants a line of text - * remove the cr/lf sequence and any trtailing spaces - * (s/[ \t\r\n]*$//) - */ - if ((char *)0 == pcWant) { - while (0 != j && isspace((int)(pcBuf[j - 1]))) { - pcBuf[--j] = '\000'; - } - Debug(1, "ReadReply: %s", pcBuf); - return j; - } if (fDebug) { - static STRING *tmpString = (STRING *) 0; - if (tmpString == (STRING *) 0) + static STRING *tmpString = (STRING *)0; + if (tmpString == (STRING *)0) tmpString = AllocString(); BuildString((char *)0, tmpString); - FmtCtlStr(pcWant, -1, tmpString); - if (strcmp(pcBuf, pcWant)) - Debug(1, "ReadReply: didn't match `%s'", tmpString->string); - else - Debug(1, "ReadReply: matched `%s'", tmpString->string); + FmtCtlStr(result->string, result->used - 1, tmpString); + CONDDEBUG((1, "ReadReply: `%s'", tmpString->string)); } - return strcmp(pcBuf, pcWant); + return result->string; } -/* call a machine master for group master ports and machine master ports - * take a list like "1782@localhost:@mentor.cc.purdue.edu:@pop.stat.purdue.edu" - * and send the given command to the group leader at 1782 - * and ask the machine master at mentor for more group leaders - * and ask the machine master at pop.stat for more group leaders - */ -static int -#if PROTOTYPES -Gather(int (*pfi) (), char *pcPorts, char *pcMaster, char *pcTo, - char *pcCmd, char *pcWho) -#else -Gather(pfi, pcPorts, pcMaster, pcTo, pcCmd, pcWho) - int (*pfi) (); - char *pcPorts, *pcMaster, *pcTo, *pcCmd, *pcWho; -#endif -{ - CONSFILE *pcf; - unsigned short j; - char *pcNext, *pcServer; - STRING *acExcg = (STRING *) 0; - struct sockaddr_in client_port; - int iRet = 0; - - if (acExcg == (STRING *) 0) - acExcg = AllocString(); - - for ( /* param */ ; '\000' != *pcPorts; pcPorts = pcNext) { - if ((char *)0 == (pcNext = strchr(pcPorts, ':'))) - pcNext = ""; - else - *pcNext++ = '\000'; - - BuildString((char *)0, acExcg); - BuildString(pcMaster, acExcg); - if ((char *)0 != (pcServer = strchr(pcPorts, '@'))) { - *pcServer++ = '\000'; - if ('\000' != *pcServer) { - BuildString((char *)0, acExcg); - BuildString(pcServer, acExcg); - } - } - - if ('\000' == *pcPorts) { - j = htons(bindPort); - } else if (!isdigit((int)(pcPorts[0]))) { - Error("%s: %s", pcMaster, pcPorts); - exit(EX_UNAVAILABLE); - } else { - j = htons((short)atoi(pcPorts)); - } - - pcf = GetPort(acExcg->string, &client_port, j); - - if (0 != ReadReply(pcf, acMesg, sizeof(acMesg), "ok\r\n")) { - int s = strlen(acMesg); - if ((s > 0) && ('\n' == acMesg[s - 1])) - acMesg[s - 1] = '\000'; - Error("%s: %s", acExcg->string, acMesg); - exit(EX_UNAVAILABLE); - } - - iRet += (*pfi) (pcf, acExcg->string, pcTo, pcCmd, pcWho); - - FileClose(&pcf); - - if ((char *)0 != pcServer) { - *pcServer = '@'; - } - } - DestroyString(acExcg); - return iRet; -} - - static int SawUrg = 0; /* when the conserver program gets the suspend sequence it will send us @@ -942,12 +681,12 @@ ProcessUrgentData(s) */ static int #if PROTOTYPES -CallUp(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcHow, - char *pcUser) +CallUp(CONSFILE *pcf, char *pcMaster, char *pcMach, char *pcHow, + char *result) #else -CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) +CallUp(pcf, pcMaster, pcMach, pcHow, result) CONSFILE *pcf; - char *pcMaster, *pcMach, *pcHow, *pcUser; + char *pcMaster, *pcMach, *pcHow, *result; #endif { int nc; @@ -957,12 +696,11 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) int justProcessedUrg = 0; if (fVerbose) { - Msg("%s to %s (%son %s)", pcHow, pcMach, fRaw ? "raw " : "", - pcMaster); + Msg("%s to %s (on %s)", pcHow, pcMach, pcMaster); } #if !defined(__CYGWIN__) # if defined(F_SETOWN) - if (-1 == fcntl(FileFDNum(pcf), F_SETOWN, getpid())) { + if (fcntl(FileFDNum(pcf), F_SETOWN, getpid()) == -1) { Error("fcntl(F_SETOWN,%d): %d: %s", getpid(), FileFDNum(pcf), strerror(errno)); } @@ -973,7 +711,7 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) /* on the HP-UX systems if different */ iTemp = -getpid(); - if (-1 == ioctl(FileFDNum(pcf), SIOCSPGRP, &iTemp)) { + if (ioctl(FileFDNum(pcf), SIOCSPGRP, &iTemp) == -1) { Error("ioctl(%d,SIOCSPGRP): %s", FileFDNum(pcf), strerror(errno)); } @@ -985,6 +723,49 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) SimpleSignal(SIGURG, OOB); #endif + /* if we are going for a particular console + * send sign-on stuff, then wait for some indication of what mode + * we got from the server (if we are the only people on we get write + * access by default, which is fine for most people). + */ + + /* how did we do, did we get a read-only or read-write? + */ + if (0 == strcmp(result, "[attached]\r\n")) { + /* OK -- we are good as gold */ + fIn = 'a'; + } else if (0 == strcmp(result, "[spy]\r\n") || + 0 == strcmp(result, "[ok]\r\n")) { + /* Humph, someone else is on + * or we have an old version of the server (4.X) + */ + fIn = 's'; + } else if (0 == strcmp(result, "[host is read-only]\r\n")) { + fIn = 'r'; + } else if (0 == strcmp(result, "[line to host is down]\r\n")) { + /* ouch, the machine is down on the server */ + fIn = '-'; + Error("%s is down", pcMach); + if (fVerbose) { + printf("[use `"); + PutCtlc(chAttn, stdout); + PutCtlc(chEsc, stdout); + printf("o\' to open console line]\n"); + } + } else if (0 == strcmp(result, "[no -- on ctl]\r\n")) { + fIn = '-'; + Error("%s is a control port", pcMach); + if (fVerbose) { + printf("[use `"); + PutCtlc(chAttn, stdout); + PutCtlc(chEsc, stdout); + printf(";\' to open a console line]\n"); + } + } else { + FilePrint(cfstdout, "%s: %s", pcMach, result); + exit(EX_UNAVAILABLE); + } + /* change escape sequence (if set on the command line) * and replay the log for the user, if asked */ @@ -992,126 +773,19 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) chAttn = DEFATTN; chEsc = DEFESC; } else { + char *r; /* tell the conserver to change escape sequences, assume OK * (we'll find out soon enough) */ sprintf(acMesg, "%c%ce%c%c", DEFATTN, DEFESC, chAttn, chEsc); - SendOut(pcf, acMesg, 5); - if (0 == ReadReply(pcf, acMesg, sizeof(acMesg), (char *)0)) { + FileWrite(pcf, acMesg, 5); + /* -bryan */ + r = ReadReply(pcf, 0); + if (strncmp(r, "[redef:", 7) != 0) { Error("protocol botch on redef of escape sequence"); exit(EX_UNAVAILABLE); } } - if (fVerbose) { - printf("Enter `"); - PutCtlc(chAttn, stdout); - PutCtlc(chEsc, stdout); - printf("?\' for help.\n"); - } - - - /* if we are going for a particular console - * send sign-on stuff, then wait for some indication of what mode - * we got from the server (if we are the only people on we get write - * access by default, which is fine for most people). - */ - if (!fRaw) { -#if HAVE_OPENSSL - sprintf(acMesg, "%c%c*", chAttn, chEsc); - SendOut(pcf, acMesg, 3); - if (0 == ReadReply(pcf, acMesg, sizeof(acMesg), "[ssl:\r\n")) { - AttemptSSL(pcf); - } - if (fReqEncryption && FileGetType(pcf) != SSLSocket) { - Error("Encryption not supported by server"); - exit(EX_UNAVAILABLE); - } -#endif - /* begin connect with who we are - */ - sprintf(acMesg, "%c%c;", chAttn, chEsc); - SendOut(pcf, acMesg, 3); - if (0 != ReadReply(pcf, acMesg, sizeof(acMesg), "[login:\r\n") && - 0 != strcmp(acMesg, "\r\n[login:\r\n")) { - int s = strlen(acMesg); - if (0 != strcmp(acMesg, "[Encryption required\r\n")) { - if ((s > 0) && ('\n' == acMesg[s - 1])) - acMesg[s - 1] = '\000'; - Error("call: %s", acMesg); - } else { - Error("Encryption required by server for login"); - } - exit(EX_UNAVAILABLE); - } - - sprintf(acMesg, "%s\r\n", pcUser); - SendOut(pcf, acMesg, strlen(acMesg)); - if (0 != ReadReply(pcf, acMesg, sizeof(acMesg), "host:\r\n")) { - int s = strlen(acMesg); - if ((s > 0) && ('\n' == acMesg[s - 1])) - acMesg[s - 1] = '\000'; - Error("%s", acMesg); - exit(EX_UNAVAILABLE); - } - - /* which host we want, and a passwd if asked for one - */ - sprintf(acMesg, "%s\r\n", pcMach); - SendOut(pcf, acMesg, strlen(acMesg)); - ReadReply(pcf, acMesg, sizeof(acMesg), (char *)0); - if (0 == strcmp(acMesg, "passwd:")) { - static STRING *tmpString = (STRING *) 0; - if (tmpString == (STRING *) 0) - tmpString = AllocString(); - BuildString((char *)0, tmpString); - sprintf(acMesg, "Enter %s@%s's password:", pcUser, pcMaster); -#if defined(HAVE_GETPASSPHRASE) - BuildString(getpassphrase(acMesg), tmpString); -#else - BuildString(getpass(acMesg), tmpString); -#endif - BuildString("\r\n", tmpString); - SendOut(pcf, tmpString->string, strlen(tmpString->string)); - ReadReply(pcf, acMesg, sizeof(acMesg), (char *)0); - } - - /* how did we do, did we get a read-only or read-write? - */ - if (0 == strcmp(acMesg, "attached]")) { - /* OK -- we are good as gold */ - fIn = 'a'; - } else if (0 == strcmp(acMesg, "spy]") || - 0 == strcmp(acMesg, "ok]")) { - /* Humph, someone else is on - * or we have an old version of the server (4.X) - */ - fIn = 's'; - } else if (0 == strcmp(acMesg, "host is read-only]")) { - fIn = 'r'; - } else if (0 == strcmp(acMesg, "line to host is down]")) { - /* ouch, the machine is down on the server */ - fIn = '-'; - Error("%s is down", pcMach); - if (fVerbose) { - printf("[use `"); - PutCtlc(chAttn, stdout); - PutCtlc(chEsc, stdout); - printf("o\' to open console line]\n"); - } - } else if (0 == strcmp(acMesg, "no -- on ctl]")) { - fIn = '-'; - Error("%s is a control port", pcMach); - if (fVerbose) { - printf("[use `"); - PutCtlc(chAttn, stdout); - PutCtlc(chEsc, stdout); - printf(";\' to open a console line]\n"); - } - } else { - Error("%s: %s", pcMach, acMesg); - exit(EX_UNAVAILABLE); - } - } printf("[Enter `"); PutCtlc(chAttn, stdout); @@ -1121,21 +795,21 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) /* if the host is not down, finish the connection, and force * the correct attachment for the user */ - if ('-' != fIn) { + if (fIn != '-') { if (fIn == 'r') { - if ('s' != *pcHow) { + if (*pcHow != 's') { Error("%s is read-only", pcMach); } - } else if (fIn != ('f' == *pcHow ? 'a' : *pcHow)) { + } else if (fIn != (*pcHow == 'f' ? 'a' : *pcHow)) { sprintf(acMesg, "%c%c%c", chAttn, chEsc, *pcHow); - SendOut(pcf, acMesg, 3); + FileWrite(pcf, acMesg, 3); } if (fReplay) { sprintf(acMesg, "%c%cr", chAttn, chEsc); - SendOut(pcf, acMesg, 3); + FileWrite(pcf, acMesg, 3); } else if (fVerbose) { sprintf(acMesg, "%c%c\022", chAttn, chEsc); - SendOut(pcf, acMesg, 3); + FileWrite(pcf, acMesg, 3); } } fflush(stdout); @@ -1151,6 +825,8 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) FD_ZERO(&rinit); FD_SET(FileFDNum(pcf), &rinit); FD_SET(0, &rinit); + if (maxfd < FileFDNum(pcf) + 1) + maxfd = FileFDNum(pcf) + 1; for (;;) { justProcessedUrg = 0; if (SawUrg) { @@ -1160,21 +836,22 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) /* reset read mask and select on it */ rmask = rinit; - while (-1 == - select(sizeof(rmask) * 8, &rmask, (fd_set *) 0, - (fd_set *) 0, (struct timeval *)0)) { - rmask = rinit; - if (SawUrg) { - ProcessUrgentData(FileFDNum(pcf)); - justProcessedUrg = 1; + if (-1 == + select(maxfd, &rmask, (fd_set *)0, (fd_set *)0, + (struct timeval *)0)) { + if (errno != EINTR) { + Error("Master(): select(): %s", strerror(errno)); + break; } + continue; } /* anything from socket? */ if (FD_ISSET(FileFDNum(pcf), &rmask)) { - if ((nc = FileRead(pcf, acMesg, sizeof(acMesg))) == 0) { + if ((nc = FileRead(pcf, acMesg, sizeof(acMesg))) < 0) { + /* if we got an error/eof after returning from suspend */ if (justProcessedUrg) { - printf("\n"); + fprintf(stderr, "\n"); Error("lost connection"); } break; @@ -1183,18 +860,24 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) for (i = 0; i < nc; ++i) acMesg[i] &= 127; } - SendOut(cfstdout, acMesg, nc); + FileWrite(cfstdout, acMesg, nc); } /* anything from stdin? */ if (FD_ISSET(0, &rmask)) { - if ((nc = read(0, acMesg, sizeof(acMesg))) == 0) - break; + if ((nc = read(0, acMesg, sizeof(acMesg))) == 0) { + if (screwy) + break; + else { + FD_SET(0, &rinit); + continue; + } + } if (fStrip) { for (i = 0; i < nc; ++i) acMesg[i] &= 127; } - SendOut(pcf, acMesg, nc); + FileWrite(pcf, acMesg, nc); } } C2Cooked(); @@ -1203,271 +886,231 @@ CallUp(pcf, pcMaster, pcMach, pcHow, pcUser) return 0; } - -/* the group leader tells is the server to connect to (ksb) - * we use CallUp to start a session with each target, or forward it +/* shouldn't need more than 3 levels of commands (but alloc 4 just 'cause) + * worst case so far: master, groups, broadcast + * (cmdarg == broadcast msg) */ -static int +char *cmds[4] = { (char *)0, (char *)0, (char *)0, (char *)0 }; +char *cmdarg = (char *)0; + +/* call a machine master for group master ports and machine master ports + * take a list like "1782@localhost:@mentor.cc.purdue.edu:@pop.stat.purdue.edu" + * and send the given command to the group leader at 1782 + * and ask the machine master at mentor for more group leaders + * and ask the machine master at pop.stat for more group leaders + */ +int #if PROTOTYPES -Indir(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcCmd, - char *pcWho) +DoCmds(char *master, char *ports, int cmdi) #else -Indir(pcf, pcMaster, pcMach, pcCmd, pcWho) - CONSFILE *pcf; - char *pcMaster, *pcMach, *pcCmd, *pcWho; +DoCmds(master, ports, cmdi) + char *master; + char *ports; + int cmdi; #endif { - char acPorts[4097]; - - /* send request for master list - */ - sprintf(acPorts, "call:%s\r\n", pcMach); - SendOut(pcf, acPorts, strlen(acPorts)); - - /* get the ports number */ - if (0 >= ReadReply(pcf, acPorts, sizeof(acPorts), (char *)0)) { - Error("master forward broken"); - exit(EX_UNAVAILABLE); - } - - if ('@' == acPorts[0]) { - static int iLimit = 0; - if (iLimit++ > 10) { - Error("forwarding level too deep!"); - return 1; - } - return Gather(Indir, acPorts, pcMaster, pcMach, pcCmd, pcWho); - } - /* to the command to each master - */ - return Gather(CallUp, acPorts, pcMaster, pcMach, pcCmd, pcWho); -} - -#define BUF_G1 1024 -#define BUF_MIN 80 -#define BUF_CHUNK (2*132) - -/* Cmd is implemented separately from above because of the need buffer (ksb) - * the ports' output. It's about the same as what's above otherwise. - * We trick lint because we have to be call compatible (prototype'd) - * the same as all the other Gather functions. - */ -static int -#if PROTOTYPES -Cmd(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcCmd, char *pcWho) -#else -Cmd(pcf, pcMaster, pcMach, pcCmd, pcWho) CONSFILE *pcf; - char *pcMaster, *pcMach, *pcCmd, *pcWho; -#endif -{ - static int iMax = 0; - static char *pcBuf = (char *)0; - int nr, iRem, i, fBrace; + char *t; + char *next; + char *server; + unsigned short port; + char *result = (char *)0; + int len; - /* setup the big buffer for the server output - */ - if ((char *)0 == pcBuf) { - iMax = BUF_G1; - if ((char *)0 == (pcBuf = calloc(BUF_G1, sizeof(char)))) { - OutOfMem(); + len = strlen(ports); + while (len > 0 && (ports[len - 1] == '\r' || ports[len - 1] == '\n')) + len--; + ports[len] = '\000'; + + for ( /* param */ ; *ports != '\000'; ports = next) { + if ((next = strchr(ports, ':')) == (char *)0) + next = ""; + else + *next++ = '\000'; + + if ((server = strchr(ports, '@')) != (char *)0) { + *server++ = '\000'; + if (*server == '\000') + server = master; + } else + server = master; + + if (*ports == '\000') { + port = htons(bindPort); + } else if (!isdigit((int)(ports[0]))) { + Error("invalid port spec for %s: `%s'", server, ports); + continue; + } else { + port = htons((short)atoi(ports)); } - } - /* send sign-on stuff, then wait for a reply, like "ok\r\n" - * before allowing a write - */ - if (*pcCmd == 'b') { - sprintf(acMesg, "%c%c%c%s:%s\r%c%c.", DEFATTN, DEFESC, *pcCmd, - pcWho, pcMach, DEFATTN, DEFESC); - SendOut(pcf, acMesg, strlen(acMesg)); - } else { - sprintf(acMesg, "%c%c%c%c%c.", DEFATTN, DEFESC, *pcCmd, DEFATTN, - DEFESC); - SendOut(pcf, acMesg, 6); - } + attemptLogin: + if ((pcf = GetPort(server, port)) == (CONSFILE *)0) + continue; - /* read the server's reply, - * We buffer until we close the connection because it - * wouldn't be fair to ask the server to keep up with - * itself :-) {if we are inside a console connection}. - */ - iRem = iMax; - i = 0; - while (0 < (nr = FileRead(pcf, pcBuf + i, iRem))) { - i += nr; - iRem -= nr; - if (iRem >= BUF_MIN) { + t = ReadReply(pcf, 0); + if (strcmp(t, "ok\r\n") != 0) { + FileClose(&pcf); + FilePrint(cfstdout, "%s: %s", server, t); continue; } - iMax += BUF_CHUNK; - if ((char *)0 == (pcBuf = realloc(pcBuf, iMax))) { - OutOfMem(); +#if HAVE_OPENSSL + FileWrite(pcf, "ssl\r\n", 5); + t = ReadReply(pcf, 0); + if (strcmp(t, "ok\r\n") == 0) { + AttemptSSL(pcf); } - iRem += BUF_CHUNK; - } - /* edit out the command lines [...] - */ - iRem = fBrace = 0; - for (nr = 0; nr < i; ++nr) { - if (0 != fBrace) { - if (']' == pcBuf[nr]) { - fBrace = 0; + if (fReqEncryption && FileGetType(pcf) != SSLSocket) { + Error("Encryption not supported by server `%s'", server); + FileClose(&pcf); + continue; + } +#endif + + BuildTmpString((char *)0); + BuildTmpString("login "); + BuildTmpString(pcUser); + t = BuildTmpString("\r\n"); + FileWrite(pcf, t, -1); + + t = ReadReply(pcf, 0); + if (strcmp(t, "passwd?\r\n") == 0) { + static int count = 0; + static STRING *tmpString = (STRING *)0; + if (tmpString == (STRING *)0) + tmpString = AllocString(); + if (tmpString->used <= 1) { + char *pass; + sprintf(acMesg, "Enter %s@%s's password: ", pcUser, + master); + pass = GetPassword(acMesg); + if (pass == (char *)0) { + Error("could not get password from tty for `%s'", + server); + FileClose(&pcf); + continue; + } + BuildString(pass, tmpString); + BuildString("\r\n", tmpString); } - continue; - } - switch (pcBuf[nr]) { - case '\r': - if (0 == iRem) - continue; - break; - case '\n': - if (0 == iRem) - continue; - putchar('\n'); - iRem = 0; - continue; - case '[': - fBrace = 1; + FileWrite(pcf, tmpString->string, tmpString->used - 1); + t = ReadReply(pcf, 0); + if (strcmp(t, "ok\r\n") != 0) { + FilePrint(cfstdout, "%s: %s", server, t); + if (++count < 3) { + BuildString((char *)0, tmpString); + goto attemptLogin; + } + Error("too many bad passwords for `%s'", server); + count = 0; + FileClose(&pcf); continue; + } else + count = 0; } - putchar(pcBuf[nr]); - iRem = 1; + + /* now that we're logged in, we can do something */ + /* if we're on the last cmd or the command is 'call' and we + * have an arg (always true if it's 'call'), then send the arg + */ + if ((cmdi == 0 || cmds[cmdi][0] == 'c') && cmdarg != (char *)0) + FilePrint(pcf, "%s %s\r\n", cmds[cmdi], cmdarg); + else + FilePrint(pcf, "%s\r\n", cmds[cmdi]); + + /* if we haven't gone down the stack, do "normal" stuff. + * if we did hit the bottom, we send the exit\r\n now so + * that the ReadReply can stop once the socket closes. + */ + if (cmdi != 0) { + t = ReadReply(pcf, 0); + /* save the result */ + if ((result = strdup(t)) == (char *)0) + OutOfMem(); + } + + /* if we're working on finding a console */ + if (cmds[cmdi][0] == 'c') { + /* did we get a redirect? */ + if (result[0] == '@' || (result[0] >= '0' && result[0] <= '9')) { + static int limit = 0; + if (limit++ > 10) { + Error("forwarding level too deep!"); + exit(EX_SOFTWARE); + } + } else if (result[0] != '[') { /* did we not get a connection? */ + FilePrint(cfstdout, "%s: %s", server, result); + FileClose(&pcf); + continue; + } else { + /* right now, we can only connect to one console, so it's ok + * to clear the password. if we were allowed to connect to + * multiple consoles (somehow), either in parallel or serial, + * we wouldn't want to do this here */ + ClearPassword(); + CallUp(pcf, server, cmdarg, cmds[0], result); + return 0; + } + } else if (cmds[cmdi][0] == 'q') { + t = ReadReply(pcf, 0); + FileWrite(cfstdout, t, -1); + if (t[0] != 'o' || t[1] != 'k') { + FileWrite(pcf, "exit\r\n", 6); + t = ReadReply(pcf, 1); + } + } else { + /* all done */ + FileWrite(pcf, "exit\r\n", 6); + t = ReadReply(pcf, cmdi == 0 ? 1 : 0); + + if (cmdi == 0) { + int len; + /* if we hit bottom, this is where we get our results */ + if ((result = strdup(t)) == (char *)0) + OutOfMem(); + len = strlen(result); + if (len > 8 && + strcmp("goodbye\r\n", result + len - 9) == 0) { + len -= 9; + *(result + len) = '\000'; + } + /* if (not 'broadcast' and not 'textmsg') or + * result doesn't start with 'ok' (only checks this if + * it's a 'broadcast' or 'textmsg') + */ + if (cmds[0][0] == 'd') { + if (result[0] != 'o' || result[1] != 'k') { + FileWrite(cfstdout, server, -1); + FileWrite(cfstdout, ": ", 2); + FileWrite(cfstdout, result, len); + } else { + disconnectCount += atoi(result + 19); + } + } else if ((cmds[0][0] != 'b' && cmds[0][0] != 't') || + (result[0] != 'o' || result[1] != 'k')) { + /* did a 'master' before this or doing a 'disconnect' */ + if (cmds[1][0] == 'm' || cmds[0][0] == 'd') { + FileWrite(cfstdout, server, -1); + FileWrite(cfstdout, ": ", 2); + } + FileWrite(cfstdout, result, len); + } + } + } + + FileClose(&pcf); + + /* this would only be true if we got extra redirects (@... above) */ + if (cmds[cmdi][0] == 'c') + DoCmds(server, result, cmdi); + else if (cmdi > 0) + DoCmds(server, result, cmdi - 1); + free(result); } - /* SendOut(1, pcBuf, i); */ - fflush(stdout); return 0; } -/* the masters tell us the group masters with a "groups" command (ksb) - */ -static int -#if PROTOTYPES -CmdGroup(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcCmd, - char *pcWho) -#else -CmdGroup(pcf, pcMaster, pcMach, pcCmd, pcWho) - CONSFILE *pcf; - char *pcMaster, *pcMach, *pcCmd, *pcWho; -#endif -{ - char acPorts[4097]; - - /* send request for master list - */ - sprintf(acPorts, "groups\r\n"); - SendOut(pcf, acPorts, strlen(acPorts)); - - /* get the ports number */ - if (0 >= ReadReply(pcf, acPorts, sizeof(acPorts), (char *)0)) { - Error("master forward broken"); - exit(EX_UNAVAILABLE); - } - if (fVerbose) { - printf("%s:\r\n", pcMaster); - } - /* to the command to each master - */ - return Gather(Cmd, acPorts, pcMaster, pcMach, pcCmd, pcWho); -} - - -/* the master tells us the machine masters with a "master" command (ksb) - * we ask each of those for the group members - */ -static int -#if PROTOTYPES -CmdMaster(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcCmd, - char *pcWho) -#else -CmdMaster(pcf, pcMaster, pcMach, pcCmd, pcWho) - CONSFILE *pcf; - char *pcMaster, *pcMach, *pcCmd, *pcWho; -#endif -{ - char acPorts[4097]; - - /* send request for master list - */ - SendOut(pcf, "master\r\n", 8); - - /* get the ports number */ - if (0 >= ReadReply(pcf, acPorts, sizeof(acPorts), (char *)0)) { - Error("master forward broken"); - exit(EX_UNAVAILABLE); - } - /* to the command to each master - */ - return Gather(CmdGroup, acPorts, pcMaster, pcMach, pcCmd, pcWho); -} - - -/* The masters tell us the group masters with a "groups" command. (ksb) - * We trick lint because we have to be call compatible (prototype'd) - * the same as all the other Gather functions. - */ -static int -#if PROTOTYPES -Ctl(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcCmd, char *pcWho) -#else -Ctl(pcf, pcMaster, pcMach, pcCmd, pcWho) - CONSFILE *pcf; - char *pcMaster, *pcMach, *pcCmd, *pcWho; -#endif -{ - char acPorts[4097]; - - /* send request for master list - */ - sprintf(acPorts, "%s:%s\r\n", pcCmd, pcMach); - SendOut(pcf, acPorts, strlen(acPorts)); - - /* get the ports number */ - if (0 >= ReadReply(pcf, acPorts, sizeof(acPorts), (char *)0)) { - Error("group leader died?"); - return 1; - } - if (fVerbose) { - printf("%s:\r\n", pcMaster); - } - printf("%s: %s\r\n", pcMaster, acPorts); - - /* to the command to each master - */ - return 0; -} - - -/* the master tells us the machine masters with a "master" command (ksb) - * we tell each of those the command we want them to do - */ -static int -#if PROTOTYPES -CtlMaster(CONSFILE * pcf, char *pcMaster, char *pcMach, char *pcCmd, - char *pcWho) -#else -CtlMaster(pcf, pcMaster, pcMach, pcCmd, pcWho) - CONSFILE *pcf; - char *pcMaster, *pcMach, *pcCmd, *pcWho; -#endif -{ - char acPorts[4097]; - - /* send request for master list - */ - SendOut(pcf, "master\r\n", 8); - - /* get the ports number */ - if (0 >= ReadReply(pcf, acPorts, sizeof(acPorts), (char *)0)) { - Error("master forward broken"); - exit(EX_UNAVAILABLE); - } - /* to the command to each master - */ - return Gather(Ctl, acPorts, pcMaster, pcMach, pcCmd, pcWho); -} - /* mainline for console client program (ksb) * setup who we are, and what our loopback addr is @@ -1485,26 +1128,25 @@ main(argc, argv) char **argv; #endif { - char *pcCmd, *pcTo; + char *pcCmd; struct passwd *pwdMe = (struct passwd *)0; int opt; int fLocal; - static STRING *acPorts = (STRING *) 0; - char *pcUser = (char *)0; - char *pcMsg = (char *)0; - int (*pfiCall) (); - static char acOpts[] = "7aAb:B:c:De:EfFGhiIl:M:p:PqQrRsSuvVwWx"; + static STRING *acPorts = (STRING *)0; + static char acOpts[] = "7aAb:B:c:d:De:EfFhiIl:M:p:PqQrRsSt:uvVwWx"; extern int optind; extern int optopt; extern char *optarg; int i; - STRING *tmpString = (STRING *) 0; + STRING *textMsg = (STRING *)0; + int cmdi; + int retval; isMultiProc = 0; /* make sure stuff DOESN'T have the pid */ - if (tmpString == (STRING *) 0) - tmpString = AllocString(); - if (acPorts == (STRING *) 0) + if (textMsg == (STRING *)0) + textMsg = AllocString(); + if (acPorts == (STRING *)0) acPorts = AllocString(); if ((char *)0 == (progname = strrchr(argv[0], '/'))) { @@ -1517,7 +1159,7 @@ main(argc, argv) */ pcCmd = (char *)0; fLocal = 0; - while (EOF != (opt = getopt(argc, argv, acOpts))) { + while ((opt = getopt(argc, argv, acOpts)) != EOF) { switch (opt) { case '7': /* strip high-bit */ fStrip = 1; @@ -1531,11 +1173,11 @@ main(argc, argv) break; case 'B': /* broadcast message */ - fReplay = 1; + fLocal = 1; /* fall through */ case 'b': pcCmd = "broadcast"; - pcMsg = optarg; + cmdarg = optarg; break; case 'c': @@ -1548,6 +1190,11 @@ main(argc, argv) fDebug++; break; + case 'd': + pcCmd = "disconnect"; + cmdarg = optarg; + break; + case 'E': #if HAVE_OPENSSL fReqEncryption = 0; @@ -1565,13 +1212,6 @@ main(argc, argv) pcCmd = "force"; break; - case 'G': - fRaw = 1; - if ((char *)0 == pcCmd) { - pcCmd = "spy"; - } - break; - case 'I': fLocal = 1; /* fall through */ @@ -1616,19 +1256,34 @@ main(argc, argv) pcCmd = "spy"; break; + case 't': + BuildString((char *)0, textMsg); + if (optarg == (char *)0 || *optarg == '\000') { + Error("no destination specified for -t", optarg); + exit(EX_UNAVAILABLE); + } else if (strchr(optarg, ' ') != (char *)0) { + Error("-t option cannot contain a space: `%s'", + optarg); + exit(EX_UNAVAILABLE); + } + BuildString("textmsg ", textMsg); + BuildString(optarg, textMsg); + pcCmd = textMsg->string; + break; + case 'u': - pcCmd = "users"; + pcCmd = "hosts"; break; case 'W': fLocal = 1; /*fallthrough */ case 'w': /* who */ - pcCmd = "groups"; + pcCmd = "group"; break; case 'x': - pcCmd = "xamine"; + pcCmd = "examine"; break; case 'v': @@ -1658,11 +1313,34 @@ main(argc, argv) exit(EX_OK); } - if (pcPort == NULL) { - Error("Severe error: pcPort is NULL???? How can that be?"); + /* finish resolving the command to do */ + if (pcCmd == (char *)0) { + pcCmd = "attach"; + } + + if (*pcCmd == 'a' || *pcCmd == 'f' || *pcCmd == 's') { + if (optind >= argc) { + Error("missing console name"); + exit(EX_UNAVAILABLE); + } + cmdarg = argv[optind++]; + } else if (*pcCmd == 't') { + if (optind >= argc) { + Error("missing message text"); + exit(EX_UNAVAILABLE); + } + cmdarg = argv[optind++]; + } + + if (optind < argc) { + Error("extra garbage on command line? (%s...)", argv[optind]); exit(EX_UNAVAILABLE); } + /* 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 (i = 0; pcPort[i] != '\000'; i++) if (!isdigit((int)pcPort[i])) @@ -1674,7 +1352,7 @@ main(argc, argv) } else { /* non-numeric only */ struct servent *pSE; - if ((struct servent *)0 == (pSE = getservbyname(pcPort, "tcp"))) { + if ((pSE = getservbyname(pcPort, "tcp")) == (struct servent *)0) { Error("getservbyname(%s): %s", pcPort, strerror(errno)); exit(EX_UNAVAILABLE); } else { @@ -1702,28 +1380,8 @@ main(argc, argv) } } - /* finish resolving the command to do, call Gather - */ - if ((char *)0 == pcCmd) { - pcCmd = "attach"; - } - if ('a' == *pcCmd || 'f' == *pcCmd || 's' == *pcCmd) { - if (optind >= argc) { - Error("missing console name"); - exit(EX_UNAVAILABLE); - } - pcTo = argv[optind++]; - } else if ('b' == *pcCmd) { - pcTo = pcMsg; - } else { - pcTo = "*"; - } - - if (optind < argc) { - Error("extra garbage on command line? (%s...)", argv[optind]); - exit(EX_UNAVAILABLE); - } + SimpleSignal(SIGPIPE, SIG_IGN); cfstdout = FileOpenFD(1, simpleFile); @@ -1735,30 +1393,26 @@ main(argc, argv) SetupSSL(); /* should only do if we want ssl - provide flag! */ #endif - if ('q' == *pcCmd) { - BuildString((char *)0, tmpString); -#if defined(HAVE_GETPASSPHRASE) - BuildString(getpassphrase("Enter root password:"), tmpString); -#else - BuildString(getpass("Enter root password:"), tmpString); -#endif - pfiCall = fLocal ? Ctl : CtlMaster; - if (tmpString->string == (char *)0) - pcTo = ""; - else - pcTo = tmpString->string; - } else if ('v' == *pcCmd) { - pfiCall = fLocal ? Ctl : CtlMaster; - } else if ('p' == *pcCmd) { - pfiCall = CtlMaster; - } else if ('a' == *pcCmd || 'f' == *pcCmd || 's' == *pcCmd) { + /* stack up the commands for DoCmds() */ + cmdi = -1; + cmds[++cmdi] = pcCmd; + + if (*pcCmd == 'q' || *pcCmd == 'v' || *pcCmd == 'p') { + if (!fLocal) + cmds[++cmdi] = "master"; + } else if (*pcCmd == 'a' || *pcCmd == 'f' || *pcCmd == 's') { ValidateEsc(); - pfiCall = Indir; - } else if ('g' == *pcCmd || 'i' == *pcCmd || 'b' == *pcCmd) { - pfiCall = fLocal ? CmdGroup : CmdMaster; + cmds[++cmdi] = "call"; } else { - pfiCall = CmdMaster; + cmds[++cmdi] = "groups"; + if (!fLocal) + cmds[++cmdi] = "master"; } - exit(Gather - (pfiCall, acPorts->string, pcInMaster, pcTo, pcCmd, pcUser)); + + retval = DoCmds(pcInMaster, acPorts->string, cmdi); + + if (*pcCmd == 'd') + FilePrint(cfstdout, "Disconnected %d users\n", disconnectCount); + + exit(retval); } diff --git a/console/console.man b/console/console.man index db37826..4429901 100644 --- a/console/console.man +++ b/console/console.man @@ -1,22 +1,50 @@ -.\" $Id: console.man,v 1.25 2003-03-04 07:53:03-08 bryan Exp $ -.TH CONSOLE 1 "Local" +.\" $Id: console.man,v 1.33 2003-09-22 08:21:31-07 bryan Exp $ +.TH CONSOLE 1 "2003-09-22" "conserver-8.0.0" "conserver" .SH NAME console \- console server client program .SH SYNOPSIS -\fBconsole\fP [\fB\-aAEfFGsS\fP] [\fB\-7Dv\fP] -[\fB\-c\fP \fIcred\fP] [\fB\-M\fP \fImach\fP] -[\fB\-p\fP \fIport\fP] [\fB\-e\fP \fIesc\fP] [\fB\-l\fP \fIuser\fP] -\fIconsole\fP +.B console +.RB [ \-aAEfFsS ] +.RB [ \-7Dv ] +.RB [ \-c +.IR cred ] +.BR [ \-M +.IR mach ] +.BR [ \-p +.IR port ] +.BR [ \-e +.IR esc ] +.BR [ \-l +.IR user ] +.I console .br -\fBconsole\fP [\fB\-hiIPrRuVwWx\fP] [\fB\-7Dv\fP] [\fB\-M\fP \fImach\fP] -[\fB\-p\fP \fIport\fP] [\fB\-\fP[\fBbB\fP] \fImessage\fP] +.B console +.RB [ \-hiIPrRuVwWx ] +.RB [ \-7Dv ] +.RB [ \-M +.IR mach ] +.RB [ \-p +.IR port ] +.RB [ \-d +.RI [ user ][\fB@\fP console ]] +.RB [ \- [ bB ] +.IR message ] +.RB [ \-t +.RI [ user ][\fB@\fP console ] +.IR message ] .br -\fBconsole\fP [\fB\-qQ\fP] [\fB\-7Dv\fP] [\fB\-M\fP \fImach\fP] -[\fB\-p\fP \fIport\fP] +.B console +.RB [ \-qQ ] +.RB [ \-7Dv ] +.RB [ \-M +.IR mach ] +.RB [ \-p +.IR port ] .SH DESCRIPTION .B Console is used to manipulate console terminals remotely or to poll running -\fBconserver\fP(8) daemons for status information. +.BR conserver (8) +daemons for status information. .PP In the first form above, .B console @@ -33,39 +61,39 @@ outputs only the requested information and exits. .B Console knows only of a primary .B conserver -host -(see the \fB\-M\fP option below), -to which it initially connects. +host (see the +.B \-M +option below), to which it initially connects. In a multi-server environment, the primary server may refer the client to a different server handling the requested console, -or it will provide a list of all servers if required -(as when +or it will provide a list of all servers if required (as when .B console is invoked with the -.RB ` \-r ' +.B \-r option). .B Console then opens connections to the appropriate server(s). It is not necessary for the user of .B console -to know which server manages which consoles, -as long as +to know which server manages which consoles, as long as .B console knows a valid primary server and all available consoles are listed in the primary server's configuration file. .SH OPTIONS .PP -Options may be given as separate arguments (e.g., \fB\-v -w\fP) -or clustered (e.g., \fB\-vw\fP). +Options may be given as separate arguments (e.g., +.B \-v +.BR \-w ) +or clustered (e.g., +.BR \-vw ). Options and their arguments may be separated by optional white space. Option arguments containing spaces or other characters special to the shell must be quoted. -.TP +.TP 11 .B \-7 -Strip the high bit off of all data received, -whether from user input or from the server, -before any processing occurs. +Strip the high bit off of all data received, whether from user +input or from the server, before any processing occurs. Disallows escape sequence characters with the high bit set. .TP .B \-a @@ -73,35 +101,63 @@ Access a console with a two-way (read-write) connection (this is the default). The connection is dropped to spy mode if someone else is attached read-write. .TP .BI \-b message -Broadcast a \fImessage\fP to all users connected to each server. +Broadcast a +.I message +to all users connected to each server. .TP .BI \-B message -Same as \fB\-b\fP but just send a \fImessage\fP to users on the primary server. +Same as +.B \-b +but just send a +.I message +to users on the primary server. .TP .BI \-c cred -Load an SSL certificate and key from the PEM encoded file \fIcred\fP. +Load an SSL certificate and key from the PEM encoded file +.IR cred . +.TP +.B \-d +Disconnect the users specified by +.IR user @ console . +You may specify the target as +.I user +(disconnect the +.IR user, +regardless of what console they are attached to), +.RI @ console +(disconnect all users attached to +.IR console ), +or +.IR user @ console +(disconnect the +.I user +attached to +.IR console ). .TP .B \-D Enable debugging output. .TP .BI \-e esc -Set the initial two-character escape sequence to -those represented by \fIesc\fP. -Any of the forms output by \fBcat\fP(1)'s \-\fBv\fP option -are accepted. The default value is ``\fB^Ec\fP''. +Set the initial two-character escape sequence to those represented by +.IR esc . +Any of the forms output by +.BR cat (1)'s +.B \-v +option are accepted. +The default value is +.RB `` ^Ec ''. .TP .B \-E -If encryption has been built into the code (\fB--with-openssl\fP), encrypted -client connections are a requirement. This option allows the client to -connect to a console over a non-encrypted connection. +If encryption has been built into the code +.RB ( --with-openssl ), +encrypted client connections are a requirement. +This option allows the client to connect to a console +over a non-encrypted connection. .TP .B \-f -Same as \fB\-a\fP except it will force any existing connection into spy mode. -.TP -.B \-G -Request a raw connection to the group control virtual console; -this is only useful for learning the protocol used by the -interactive sequence. +Same as +.B \-a +except it will force any existing connection into spy mode. .TP .B \-h Display a brief help message. @@ -110,54 +166,103 @@ Display a brief help message. Display information in a machine-parseable format (see below for the details). .TP .B \-I -Same as \fB\-i\fP but just acts on the primary server. +Same as +.B \-i +but just acts on the primary server. .TP .BI \-l user -Set the login name used for authentication to \fIuser\fP. -By default, \fBconsole\fP uses $USER if its uid matches the user's real uid, +Set the login name used for authentication to +.IR user . +By default, +.B console +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 -The \fBconsole\fP client program polls \fImach\fP as the primary server, -rather than the default set at compile time (typically ``\fBconsole\fP''). -The default \fImach\fP may be changed at compile time using the -\fB--with-master\fP option. +The +.B console +client program polls +.I mach +as the primary server, +rather than the default set at compile time (typically +.RB `` console ''). +The default +.I mach +may be changed at compile time using the +.B --with-master +option. .TP .BI \-p port -Set the port to connect to. This may be either a port number -or a service name. The default \fIport\fP may be changed at compile time -using the \fB--with-port\fP option. +Set the port to connect to. +This may be either a port number +or a service name. +The default +.I port +may be changed at compile time +using the +.B --with-port +option. .TP .B \-P Display the pid of the master daemon process on each server. .TP .B \-q -The \fBconsole\fP client connects to each server to request that the -server daemon quit (shut down). The root password of the host(s) -running conserver is required unless the local host is listed as -``trusted'' in the conserver.cf file; in that case, just -press . +The +.B console +client connects to each server to request that the +server daemon quit (shut down). +The root password of the host(s) running conserver is required +unless the local host is listed as ``trusted'' in the +conserver.cf file; in that case, just press . .TP .B \-Q -Same as \fB\-q\fP but just acts on the primary server. +Same as +.B \-q +but just acts on the primary server. .TP .B \-r -Display daemon versions. The \fBconsole\fP client connects to each +Display daemon versions. +The +.B console +client connects to each server to request its version information. .TP .B \-R -Same as \fB\-r\fP but just acts on the primary server. +Same as +.B \-r +but just acts on the primary server. .TP .B \-s Request a read-only (spy mode) connection. In this mode all the escape sequences (below) work, or report errors, but all other keyboard input is discarded. .TP +.B \-t +Send a text +.I message +to +.IR user @ console . +You may specify the target as +.I user +(send to +.IR user, +regardless of what console they are attached to), +.RI @ console +(send to all users attached to +.IR console ), +or +.IR user @ console +(send to +.I user +attached to +.IR console ). +.TP .B \-u Show a list of all consoles with status (`up' or `down') -and attached users (\fIuser\fP@\fIhost\fP if attached read-write, -`' if only users in spy mode, or `'). +and attached users +.RI ( user @ host +if attached read-write, `' if only users in spy mode, or `'). .TP .B \-v Be more verbose when building the connection(s). @@ -170,77 +275,101 @@ and then exit. .TP .B \-w Show a list of all who are currently connected to consoles, -including the hostnames where the \fBconsole\fP connections originate -and the idle times. This is useful to see if anybody is actively +including the hostnames where the +.B console +connections originate and the idle times. +This is useful to see if anybody is actively using the console system if it becomes necessary to shut down -\fBconserver\fP. +.BR conserver . .TP .B \-W -Same as \fB\-w\fP but just acts on the primary server. +Same as +.B \-w +but just acts on the primary server. .TP .B \-x Show a list of consoles and devices. .PP -The \fB\-A\fP, \fB\-F\fP, or \fB\-S\fP options have the same effect as -their lower-case variants. +The +.BR \-A , +.BR \-F ", or" +.B \-S +options have the same effect as their lower-case variants. In addition, they each request the last 20 lines of the console output after -making the connection (as if `\fB^Ecr\fP' were typed). +making the connection (as if +.RB ` ^Ecr ' +were typed). .PP -The \fB-i\fP option outputs information regarding each console in -ten colon-separated fields. +The +.B \-i +option outputs information regarding each console in 12 colon-separated fields. .TP -.B name +.I name The name of the console. .TP -.B hostname,pid,socket +.I hostname,pid,socket The hostname, pid, and socket number of the child process managing the console. .TP -.B type -The type of console. Values will be a `/' for a local device, `|' for +.I type +The type of console. +Values will be a `/' for a local device, `|' for a command, or `!' for a remote port. .TP -.B console-details -The details regarding the console. The values here (all comma seperated) -depend on the type of the console. Local devices will have values of -the device file, baud rate, and file descriptor for the device. +.I console-details +The details regarding the console. +The values here (all comma seperated) depend on the type of the console. +Local devices will have values of the device file, baud rate, and +file descriptor for the device. Commands will have values of the command, the command's pid, the pseudo-tty, and file descriptor for the pseudo-tty. Remote ports will have values of the remote hostname, remote port number, and file descriptor for the socket connection. .TP -.B users-list -The details of each user connected to the console. The details for each +.I users-list +The details of each user connected to the console. +The details for each user are an `@' seperated list of `w', `r', or `s' (for read-write, read-only, or suspended), username, hostname the user is on, the user's idle time, and (for `r' and `s' users only) ``rw'' or ``ro'' (if the user wants -read-write mode or not). Each user bundle is seperated by commas. +read-write mode or not). +Each user bundle is seperated by commas. .TP -.B state -The state of the console. Values with either be ``up'' or ``down''. +.I state +The state of the console. +Values with either be ``up'' or ``down''. .TP -.B perm -This value will either be ``rw'' or ``ro''. It will only be ``ro'' if +.I perm +This value will either be ``rw'' or ``ro''. +It will only be ``ro'' if the console is a local device (`/' type) and the permissions are such that the server can open the file for read, but not write. .TP -.B logfile-details -The details regarding the logging for the console. The comma seperated +.I logfile-details +The details regarding the logging for the console. +The comma seperated values will be the logfile, ``log'' or ``nolog'' (if logging is on or not - toggled via ^EcL), ``act'' or ``noact'' (if activity logging is enabled or not - the `a' timestamp option), the timestamp interval, and the file descriptor of the logfile. .TP -.B break +.I break The default break sequence used for the console. .TP -.B reup +.I reup If the console is currently down and the automatic reconnection code is at work, it will have the value of ``autoup'', otherwise it will be ``noautoup''. +.TP +.I aliases +The console aliases are presented in a comma seperated list. +.TP +.I options +The active options for the console are presented in a comma seperated list. .SH "ESCAPE SEQUENCES" The connection can be controlled by a two-character escape sequence, followed -by a command. The default escape sequence is ``control-E c'' +by a command. +The default escape sequence is ``control-E c'' (octal 005 143). (The escape sequences are actually processed by the server; see the .BR conserver (8) @@ -248,56 +377,81 @@ man page for more information.) Commands are: .sp .PD 0 -.IP a +.TP 13 +.B a attach read-write if nobody already is -.IP b +.TP +.B b send broadcast message to all users on this console -.IP c +.TP +.B c toggle flow control (don't do this) -.IP d +.TP +.B d down the current console -.IP e\fIcc\fP +.TP +.BI e cc change the escape sequence to the next two characters -.IP f +.TP +.B f forcibly attach read-write -.IP g +.TP +.B g group info -.IP L +.TP +.B L toggle logging on/off -.IP l? +.TP +.B l? list the break sequences available -.IP l0 +.TP +.B l0 send the break sequence associated with this console -.IP l1-9 +.TP +.B l1-9 send the specific break sequence -.IP o +.TP +.B o close (if open) and reopen the line (to clear errors (silo overflows)) and the log file -.IP p +.TP +.B p replay the last 60 lines of output -.IP r +.TP +.B r replay the last 20 lines of output -.IP s +.TP +.B s switch to spy mode (read-only) -.IP u +.TP +.B u show status of hosts/users in this group -.IP v +.TP +.B v show the version of the group server -.IP w +.TP +.B w who is using this console -.IP x +.TP +.B x examine this group's devices and modes -.IP z +.TP +.B z suspend this connection -.IP ? +.TP +.B ? display list of commands -.IP "^M (return)" +.TP +.BR ^M " (return)" continue, ignore the escape sequence -.IP "^R (ctrl-R)" +.TP +.BR ^R " (ctrl-R)" replay the last line only -.IP \e\\fIooo\fP -send character having octal code \fIooo\fP -(must specify three octal digits) +.TP +.BI \e ooo +send character having octal code +.IR ooo " (must" +specify three octal digits) .IP \. disconnect .PD @@ -307,73 +461,82 @@ will be discarded. Note that a line break or a down command can only be sent from a full two-way attachment. To send the escape sequence through the connection one must redefine -the outer escape sequence, or use \fB^Ec\\\fP\fIooo\fP to send the +the outer escape sequence, or use +.BI ^Ec\e ooo +to send the first escape character before typing the second character directly. .PP -In the \fB\-u\fP output, the login ``'' indicates no one is +In the +.B \-u +output, the login ``'' indicates no one is viewing that console, and the login ``'' indicates that -no one has a full two-way attachment. When no one is attached to -a console its output is cloned to the stdout of the server process -if \fBconserver\fP was started with the \fB\-u\fP option. +no one has a full two-way attachment. +When no one is attached to +a console its output is cloned to the stdout of the server process if +.B conserver +was started with the +.B \-u +option. .SH EXAMPLES -.TP +.TP 15 console \-u Outputs something like: -.sp -.RS -.ta 18n 24n -dumb up -.br -expert up ksb@mentor -.br -tyro up -.br -mentor up -.br -sage up fine@cis -.DT -.RE .IP -The \fB\fP indicates no one is viewing \fIdumb\fP or \fImentor\fP, -the \fB\fP indicates only read-only connections exist for \fItyro\fP, +.ft CR +.nf +dumb up +expert up ksb@mentor +tyro up +mentor up +sage up fine@cis +.fi +.ft +.IP +The +.B +indicates no one is viewing +.IR dumb +or +.IR mentor , +the +.B +indicates only read-only connections exist for +.IR tyro , +and other +.IR login @ host +entries indicate users attached read-write to +.I sage and -other \fIlogin\fP@\fIhost\fP entries indicate users attached read-write to -\fIsage\fP and \fIexpert\fP. +.IR expert . .TP console \-w Outputs something like: -.sp -.RS -.ta 18n 26n 32n -ksb@extra attach 2days expert -.br -file@cis attach 21:46 sage -.br -dmr@alice spy \00:04 tyro -.DT -.RE +.IP +.ft CR +.nf +ksb@extra attach 2days expert +file@cis attach 21:46 sage +dmr@alice spy \00:04 tyro +.fi +.ft .IP The third column is the idle time of the user. -Either \fIhours\fP:\fIminutes\fP or number of days is displayed. +Either +.IR hours : minutes +or number of days is displayed. .TP -console \-e \*(lq^[1\*(rq lv426 +console \-e "^[1" lv426 Requests a connection to the host ``lv426'' with the escape characters set to ``escape one''. .SH BUGS -SSL encryption only occurs when connecting to a single console, not -on all client/server activity. The \fB-q\fP/\fB-Q\fP quit command will -pass the root password in the clear. Other info-type -options (like \fB-i\fP, \fB-w\fP, etc) -are all sent unencrypted as well. This should be fixed soon. -.PP It is possible to create a loop of console connections, with ugly results. -Never run \fBconsole\fP from within a console connection (unless you set each +Never run +.B console +from within a console connection (unless you set each escape sequence differently). .PP -The \fB\-G\fP option doesn't help to explain how connections get built. -.PP -I'm sure there are more, I just don't know where they are. Please -let me know if you find any. +I'm sure there are more, I just don't know where they are. +Please let me know if you find any. .SH AUTHORS Thomas A. Fine, Ohio State Computer Science .br diff --git a/console/getpassword.c b/console/getpassword.c new file mode 100644 index 0000000..b81f0f9 --- /dev/null +++ b/console/getpassword.c @@ -0,0 +1,159 @@ +/* + * $Id: getpassword.c,v 1.6 2003-09-12 10:36:19-07 bryan Exp $ + * + * Copyright conserver.com, 2000 + * + * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) + * + * Copyright GNAC, Inc., 1998 + */ + +#include + +#include + +#include +#include + + +/* the next two routines assure that the users tty is in the + * correct mode for us to do our thing + */ +static int screwy = 0; +static struct termios o_tios; +/* this holds the password given to us by the user */ +static STRING *pass = (STRING *)0; + + +/* + * show characters that are already tty processed, + * and read characters before cononical processing + * we really use cbreak at PUCC because we need even parity... + */ +static void +#if PROTOTYPES +C2Raw(int fd) +#else +C2Raw(fd) + int fd; +#endif +{ + struct termios n_tios; + + if (!isatty(fd) || 0 != screwy) + return; + + if (0 != tcgetattr(fd, &o_tios)) { + Error("tcgetattr(%d): %s", fd, strerror(errno)); + exit(EX_UNAVAILABLE); + } + n_tios = o_tios; + n_tios.c_iflag &= ~(IUCLC | IXON); + n_tios.c_oflag &= ~OPOST; + n_tios.c_lflag &= ~(ISIG | ECHO | IEXTEN); + n_tios.c_cc[VMIN] = 1; + n_tios.c_cc[VTIME] = 0; + if (0 != tcsetattr(fd, TCSANOW, &n_tios)) { + Error("tcsetattr(%d, TCSANOW): %s", fd, strerror(errno)); + exit(EX_UNAVAILABLE); + } + screwy = 1; +} + +/* + * put the tty back as it was, however that was + */ +static void +#if PROTOTYPES +C2Normal(int fd) +#else +C2Normal(fd) + int fd; +#endif +{ + if (!screwy) + return; + tcsetattr(fd, TCSANOW, &o_tios); + screwy = 0; +} + +char * +#if PROTOTYPES +GetPassword(char *prompt) +#else +GetPassword(prompt) + char *prompt; +#endif +{ + int fd; + int nc; + char buf[BUFSIZ]; + int done = 0; + + if (prompt == (char *)0) + prompt = ""; + if ((pass = AllocString()) == (STRING *)0) + OutOfMem(); + BuildString((char *)0, pass); + + if ((fd = open("/dev/tty", O_RDWR)) == -1) { + Error("could not open `/dev/tty': %s", strerror(errno)); + return (char *)0; + } + + C2Raw(fd); + write(fd, prompt, strlen(prompt)); + while (!done) { + int i; + if ((nc = read(0, buf, sizeof(buf))) == 0) + break; + for (i = 0; i < nc; ++i) { + if (buf[i] == 0x0d || buf[i] == 0x0a) { + /* CR, NL */ + done = 1; + break; + } else + BuildStringChar(buf[i], pass); + } + } + C2Normal(fd); + /* + { + static STRING *c = (STRING *) 0; + if ((c = AllocString()) == (STRING *) 0) + OutOfMem(); + write(fd, "\n'", 2); + if (pass->used) { + FmtCtlStr(pass->string, pass->used - 1, c); + write(fd, c->string, c->used - 1); + } + write(fd, "'\n", 2); + } + */ + write(fd, "\n", 1); + close(fd); + /* this way a (char*)0 is only returned on error */ + if (pass->string == (char *)0) + return ""; + else + return pass->string; +} + +void +#if PROTOTYPES +ClearPassword(void) +#else +ClearPassword() +#endif +{ + if (pass == (STRING *)0 || pass->allocated == 0) + return; + +#if HAVE_MEMSET + memset((void *)(pass->string), '\000', pass->allocated); +#else + bzero((char *)(pass->string), pass->allocated); +#endif + + BuildString((char *)0, pass); +} diff --git a/console/getpassword.h b/console/getpassword.h new file mode 100644 index 0000000..f8690bd --- /dev/null +++ b/console/getpassword.h @@ -0,0 +1,10 @@ +/* + * $Id: getpassword.h,v 1.3 2003-09-11 02:10:58-07 bryan Exp $ + * + * Copyright conserver.com, 2000 + * + * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) + */ + +extern char *GetPassword PARAMS((char *)); +extern void *ClearPassword PARAMS((void)); diff --git a/contrib/maketestcerts b/contrib/maketestcerts index 509fb15..fb43e39 100755 --- a/contrib/maketestcerts +++ b/contrib/maketestcerts @@ -5,8 +5,10 @@ # for conserver and it's OpenSSL bits. It's far from perfect...or useful # outside of my own purposes. If this helps, cool. In the end I put the # rootcert.pem file in my global certs directory (OPENSSL_ROOT/ssl/certs), -# point the server to server.pem and point the client at client.pem. -# Ugly, yeah, but it's an ok test. +# point the server to server.pem and point the client at client.pem. I +# then run the c_rehash command (I supposed it helps or is important). +# When it asks for a passphrase, use 'pass', otherwise this script won't +# work. Ugly, yeah, but it's an ok test. # [ -f rootreq.pem -a -f rootkey.pem ] || cat < test.out 2>&1 else - (echo "$1" && sleep 2) | \ + echo "$1" | \ ../console/console -M 127.0.0.1 -p 7777 shell > test.out 2>&1 fi if [ "$record" ]; then @@ -31,7 +34,7 @@ dotest() if [ -f results/test$testnum ]; then if diff -i test.out results/test$testnum >test$testnum.diff 2>&1; then echo "succeded" - rm test$testnum.diff + rm -f test$testnum.diff else echo "failed (diffs in test$testnum.diff)" exitval=1 @@ -39,7 +42,7 @@ dotest() else echo "unknown (not recorded)" fi - rm test.out + rm -f test.out fi } @@ -57,6 +60,7 @@ else fi $ECHO "starting conserver...$EE" +rm -f c.cf cp test1.cf c.cf ../conserver/conserver -M 127.0.0.1 -p 7777 -v -C c.cf \ -P test.passwd -m 32 > conserver.log 2>&1 & @@ -75,6 +79,7 @@ dotest 'cdc.' dotest 'coc.' echo "moving in second config file" +rm -f c.cf cp test2.cf c.cf kill -1 $pid sleep 3 @@ -85,4 +90,8 @@ 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 -P | sed -e 's/:.*//'" +dotest EVAL "../console/console -M 127.0.0.1 -p 7777 -x | sed -e 's/ on [^ ]* */ on /'" + cleanup diff --git a/test/results/test11 b/test/results/test11 index fa846ea..e6efc1a 100644 --- a/test/results/test11 +++ b/test/results/test11 @@ -1,16 +1,2 @@ -[Enter `^Ec?' for help] -[help] - . disconnect a attach read/write - b send broadcast message c toggle flow control - d down a console e change escape sequence - f force attach read/write g group info - i information dump L toggle logging on/off - l? break sequence list l0 send break per config file - l1-9 send specific break sequence o (re)open the tty and log file - p replay the last 60 lines r replay the last 20 lines - s spy read only u show host status - v show version info w who is on this console - x show console baud info z suspend the connection - ignore/abort command ? print this message - ^R replay the last line \ooo send character by octal code +[Enter `tu?' for help] [disconnect] diff --git a/test/results/test12 b/test/results/test12 index 2655985..7b9ad53 100644 --- a/test/results/test12 +++ b/test/results/test12 @@ -1,8 +1 @@ -[Enter `^Ec?' for help] -[halt list] - 0 `\z' - 1 `\z' - 2 `\r~^b' - 3 `#.reset -x\r' - 4 `hiya there\r' -[disconnect] +127.0.0.1 diff --git a/test/results/test13 b/test/results/test13 index e5705ba..4fe7cfb 100644 --- a/test/results/test13 +++ b/test/results/test13 @@ -1,3 +1,3 @@ -[Enter `^Ec?' for help] -[line down] -[disconnect] + shellb on at Local + shella on at Local + shell on at Local diff --git a/test/results/test14 b/test/results/test14 deleted file mode 100644 index c41b64a..0000000 --- a/test/results/test14 +++ /dev/null @@ -1,4 +0,0 @@ -console: shell is down -[Enter `^Ec?' for help] -[up -- attached] -[disconnect] diff --git a/test/results/test3 b/test/results/test3 index 8c404ae..07f7289 100644 --- a/test/results/test3 +++ b/test/results/test3 @@ -1,8 +1,9 @@ [Enter `^Ec?' for help] [halt list] - 0 `\z' - 1 `\z' - 2 `\r~^b' - 3 `#.reset -x\r' - 5 `\rtest\r' + 0 - 250ms, `\z' + 1 - 250ms, `\z' + 2 - 250ms, `\r~^b' + 3 - 250ms, `#.' + 4 - 600ms, `\r\d~\d^b' + 5 - 250ms, `\rtest\r' [disconnect] diff --git a/test/results/test8 b/test/results/test8 index 2655985..64f0d60 100644 --- a/test/results/test8 +++ b/test/results/test8 @@ -1,8 +1,8 @@ [Enter `^Ec?' for help] [halt list] - 0 `\z' - 1 `\z' - 2 `\r~^b' - 3 `#.reset -x\r' - 4 `hiya there\r' + 0 - 250ms, `\z' + 1 - 250ms, `\z' + 2 - 250ms, `\r~^b' + 3 - 250ms, `#.' + 4 - 250ms, `hiya there\r' [disconnect] diff --git a/test/test.cf b/test/test.cf index 7e54cc5..6c52d14 100644 --- a/test/test.cf +++ b/test/test.cf @@ -1,7 +1,29 @@ # test conserver config file -LOGDIR=. -BREAK5=\rtest\r -shell:|:9600p:&.log:5 -shell2:|::shell2.log:2 -%% -trusted: 127.0.0.1 +default full { + rw *; +} +default * { + logfile ./&; + timestamp ""; + include full; +} +break 5 { + string "\rtest\r"; +} +console shell { + master localhost; + logfile ./&.log; + timestamp 5; + type exec; + exec ""; +} +console shell2 { + master localhost; + logfile ./shell2.log; + timestamp 2; + type exec; + exec ""; +} +access * { + trusted 127.0.0.1; +} diff --git a/test/test1.cf b/test/test1.cf index 7e54cc5..aeaadc1 100644 --- a/test/test1.cf +++ b/test/test1.cf @@ -1,7 +1,29 @@ # test conserver config file -LOGDIR=. -BREAK5=\rtest\r -shell:|:9600p:&.log:5 -shell2:|::shell2.log:2 -%% -trusted: 127.0.0.1 +default full { + rw *; +} +default * { + logfile ./&; + timestamp ""; + include full; +} +break 5 { + string "\rtest\r"; +} +console shell { + master 127.0.0.1; + logfile ./&.log; + timestamp 5; + type exec; + exec ""; +} +console shell2 { + master 127.0.0.1; + logfile ./shell2.log; + timestamp 2; + type exec; + exec ""; +} +access * { + trusted 127.0.0.1; +} diff --git a/test/test2.cf b/test/test2.cf index 978d406..f0f8755 100644 --- a/test/test2.cf +++ b/test/test2.cf @@ -1,8 +1,35 @@ # test conserver config file -LOGDIR=. -BREAK4=hiya there\r -shell:|:9600p:&.log:5 -shella:|::&.log:5 -shellb:|::&.log: -%% -trusted: 127.0.0.1 +default full { + rw *; +} +default * { + logfile ./&; + timestamp ""; + include full; +} +break 4 { + string "hiya there\r"; +} +console shell { + master 127.0.0.1; + logfile ./&.log; + timestamp 5; + type exec; + exec ""; +} +console shella { + master 127.0.0.1; + logfile ./&.log; + timestamp 5; + type exec; + exec ""; +} +console shellb { + master 127.0.0.1; + logfile ./&.log; + type exec; + exec ""; +} +access * { + trusted 127.0.0.1; +}