From decc2f8c4f99eaf3401e462f9d6c1cfddb6035eb Mon Sep 17 00:00:00 2001 From: Bryan Stansell Date: Fri, 18 Dec 1998 15:12:55 -0800 Subject: [PATCH] Imported from conserver-GNAC-6.05.tar.gz --- autologin/INSTALL | 64 ++ autologin/Makefile | 83 ++ autologin/README | 13 + autologin/autologin.c | 654 ++++++++++++++ autologin/autologin.m | 57 ++ autologin/autologin.man | 141 +++ autologin/main.c | 354 ++++++++ autologin/main.h | 15 + conserver.cf/INSTALL | 26 + conserver.cf/Makefile | 59 ++ conserver.cf/README | 16 + conserver.cf/conserver.cf | 76 ++ conserver.cf/conserver.cf.5l | 96 ++ conserver.cf/dummy.cf | 22 + conserver.cf/label.ps | 188 ++++ conserver.cf/test.cf | 23 + conserver/INSTALL | 114 +++ conserver/Makefile | 109 +++ conserver/README | 73 ++ conserver/Sun-serial | 44 + conserver/TODO | 8 + conserver/access.c | 181 ++++ conserver/access.h | 48 + conserver/client.c | 297 ++++++ conserver/client.h | 72 ++ conserver/cons-gnac.h | 350 ++++++++ conserver/cons-test.h | 351 ++++++++ conserver/cons.h | 1 + conserver/consent.c | 710 +++++++++++++++ conserver/consent.h | 89 ++ conserver/conserver.8l | 78 ++ conserver/conserver.man | 78 ++ conserver/conserver.passwd | 4 + conserver/fallback.c | 234 +++++ conserver/group.c | 1643 ++++++++++++++++++++++++++++++++++ conserver/group.h | 42 + conserver/identd.c | 179 ++++ conserver/init.script | 26 + conserver/main.c | 380 ++++++++ conserver/main.h | 43 + conserver/master.c | 453 ++++++++++ conserver/master.h | 32 + conserver/readcfg.c | 384 ++++++++ conserver/readcfg.h | 47 + conserver/stamper.sh | 44 + conserver/version.h | 1 + console/INSTALL | 35 + console/Makefile | 81 ++ console/README | 67 ++ console/console.8l | 185 ++++ console/console.c | 1317 +++++++++++++++++++++++++++ console/console.man | 185 ++++ 52 files changed, 9872 insertions(+) create mode 100644 autologin/INSTALL create mode 100644 autologin/Makefile create mode 100644 autologin/README create mode 100644 autologin/autologin.c create mode 100644 autologin/autologin.m create mode 100644 autologin/autologin.man create mode 100644 autologin/main.c create mode 100644 autologin/main.h create mode 100644 conserver.cf/INSTALL create mode 100644 conserver.cf/Makefile create mode 100644 conserver.cf/README create mode 100644 conserver.cf/conserver.cf create mode 100644 conserver.cf/conserver.cf.5l create mode 100644 conserver.cf/dummy.cf create mode 100644 conserver.cf/label.ps create mode 100644 conserver.cf/test.cf create mode 100644 conserver/INSTALL create mode 100644 conserver/Makefile create mode 100644 conserver/README create mode 100644 conserver/Sun-serial create mode 100644 conserver/TODO create mode 100644 conserver/access.c create mode 100644 conserver/access.h create mode 100644 conserver/client.c create mode 100644 conserver/client.h create mode 100644 conserver/cons-gnac.h create mode 100644 conserver/cons-test.h create mode 120000 conserver/cons.h create mode 100644 conserver/consent.c create mode 100644 conserver/consent.h create mode 100644 conserver/conserver.8l create mode 100644 conserver/conserver.man create mode 100644 conserver/conserver.passwd create mode 100644 conserver/fallback.c create mode 100644 conserver/group.c create mode 100644 conserver/group.h create mode 100644 conserver/identd.c create mode 100755 conserver/init.script create mode 100644 conserver/main.c create mode 100644 conserver/main.h create mode 100644 conserver/master.c create mode 100644 conserver/master.h create mode 100644 conserver/readcfg.c create mode 100644 conserver/readcfg.h create mode 100644 conserver/stamper.sh create mode 100644 conserver/version.h create mode 100644 console/INSTALL create mode 100644 console/Makefile create mode 100644 console/README create mode 100644 console/console.8l create mode 100644 console/console.c create mode 100644 console/console.man diff --git a/autologin/INSTALL b/autologin/INSTALL new file mode 100644 index 0000000..558bc74 --- /dev/null +++ b/autologin/INSTALL @@ -0,0 +1,64 @@ +# $Id: INSTALL,v 1.3 94/07/11 12:38:19 ksb Exp $ + +To install this program you need root access and access to the physical +console of the machine (either through the console server or via the physical +world). + +First compile this program and install it as /etc/autologin or +/usr/local/etc/autologin. If `/' is the only file system mounted sometimes +you'll have to use the /etc directory. + +OK. Then login on the console as root and run + # exec /etc/autologin -l root + +if you get a prompt back with no warnings things look good. Next try +to force *your* account on the console (replace `ME' with your account): + # finger -s + ... + # exec /etc/autologin -l ME + $ finger -s + ... + +You should have seen root on the console the first time you ran finger and +`ME' on the console the second. + +If you got this far we are ready to make the leap. Exit the autologin shell +as `ME' and login as root *on another terminal*. Edit /etc/inittab on a +System V machine + + cons2:2:respawn:/usr/local/etc/autologin -t/dev/tty0 -lroot >/dev/console 2>&1 +or + co:2:respawn:/usr/local/etc/autologin -t/dev/console -lroot + + +or on an RIOS run commands like: + mkitab "cons0:013456789:respawn:/etc/getty /dev/console" + mkitab "cons2:2:respawn:/usr/local/etc/autologin -t/dev/tty0 -lroot -gsystem >/dev/console 2>&1" + chitab "cons:0123456789:off:/etc/getty /dev/console" + chcons -a login=disable + + +if you are running SunOS edit /etc/ttytab and comment out the line for the +console and add a new one for autologin: + #console "/usr/etc/getty cons8" unknown on local + console "/usr/local/etc/autologin -lroot -t" xterm on local secure + +In either case restart init on the port now + kill -1 1 +or + telinit 2 +or what ever local custom sez. + +One of these will look right to you. + + +You should get a root shell on the console that you can exit and it will just +come back. When the machine reboots it should stick the same shell up. You +can make the login name here be `ops' or some other `operator' account to run +backups. We use `root'. + + + +-- +"We've got all your slack" -- net.flamer +kayessbee, Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb diff --git a/autologin/Makefile b/autologin/Makefile new file mode 100644 index 0000000..ff1ce8b --- /dev/null +++ b/autologin/Makefile @@ -0,0 +1,83 @@ +# +# $Id: Make.host,v 1.13 94/06/03 15:32:46 nuspl Exp $ +# +# Makefile for autologin +# +# Jeff W. Stewart, Purdue University Computing Center +# + +DESTDIR= +BINDIR= ${DESTDIR}/usr/local/etc + +INCLUDE= +DEBUG= -g +DEFS= -DPUCC -DSUN5 +CFLAGS= ${DEBUG} ${DEFS} ${INCLUDE} + +GENC= main.c +GENH= main.h +GEN= ${GENC} ${GENH} +HDR= +SRC= autologin.c +OBJ= autologin.o main.o +SOURCE= README autologin.man autologin.m Makefile ${SRC} ${HDR} + + + +all: autologin + +autologin: ${OBJ} + ${CC} ${CFLAGS} -o autologin ${OBJ} + +main.h: main.c + +main.c: autologin.m + mkcmd std_help.m std_version.m autologin.m + -(cmp -s prog.c main.c || (cp prog.c main.c && echo main.c updated)) + -(cmp -s prog.h main.h || (cp prog.h main.h && echo main.h updated)) + rm -f prog.[ch] + +# On keep (EPIX), putenv.o is extracted (ar x) from /usr/lib/libc.a +# and setgroups.o is extracted from libbsd.a +# +putenv.o: + ar x /usr/lib/libc.a $@ + +setgroups.o: + ar x /usr/lib/libbsd.a $@ + +getut.o: + ar x /sysv/usr/lib/libc.a $@ + +clean: FRC + rm -f autologin *.o errs core Makefile.bak a.out lint.errs ${GEN} + +lint: ${HDR} ${SRC} ${GEN} FRC + lint -h ${CDEFS} ${INCLUDE} ${GEN} ${SRC} + +install: all + install -c -s -m 755 autologin ${BINDIR} + +distrib: + distrib -c ${BINDIR}/autologin + +depend: ${HDR} ${SRC} ${GEN} + maketd -a ${HDR} ${SRC} ${GEN} + +spotless: clean + rcsclean Makefile ${HDR} ${SRC} + +source: ${SOURCE} + +${SOURCE}: + co -q $@ + +FRC: + +# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT + +main.o: main.c + +autologin.o: autologin.c main.h + +# *** Do not add anything here - It will go away. *** diff --git a/autologin/README b/autologin/README new file mode 100644 index 0000000..f6d0705 --- /dev/null +++ b/autologin/README @@ -0,0 +1,13 @@ +# $Id: README,v 1.3 93/04/21 16:13:37 ksb Exp $ + +This program can be used to put a root shell on the console at boot time. +See the manual page. + +ksb + +Ports to: HOST OS CDEFS + SUN3 4.1.1 -DSUNOS + SUN4 4.1.2 -DSUNOS + V386 ? -DSRM + EPIX ? -DEPIX -systype posix -I/usr/include (+ extra .o files) + IBMR2 -DIBMR2 diff --git a/autologin/autologin.c b/autologin/autologin.c new file mode 100644 index 0000000..feb3ae4 --- /dev/null +++ b/autologin/autologin.c @@ -0,0 +1,654 @@ +/* + * Perform an auto-login on a specified tty port. + * + * autologin [-u] [-c] [-e] [-g] -l -t + * + * Jeff W. Stewart - Purdue University Computing Center + * + * some of the ideas in this code are based on the Ohio State + * console server as re-coded by Kevin Braunsdorf (PUCC) + * + * This program was written to be run out of inittab. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#if !defined IBMR2 +extern char *sys_errlist[]; +#define strerror(Me) (sys_errlist[Me]) +#endif + +#define NEED_PUTENV (!(defined(IBMR2) || defined(EPIX) || defined(SUNOS) || defined(SUN5))) + +#if S81 +#include +#else +#include +#endif + +#if SUN5 +#define USE_UTENT 1 +#include +#include + +static int +getdtablesize() +{ + auto struct rlimit rl; + + (void)getrlimit(RLIMIT_NOFILE, &rl); + return rl.rlim_cur; +} +#endif + +/* yucky kludges + */ +#ifdef EPIX +#include "/bsd43/usr/include/ttyent.h" +#include +#define NGROUPS_MAX 8 +#define getsid(Mp) (Mp) +#define getdtablesize() 64 +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +typedef int mode_t; +extern struct passwd *getpwnam(); +extern struct group *getgrnam(); +#define USE_TC 1 +#define USE_UTENT 1 +#else + +#if defined IBMR2 +#include +#define setsid() getpid() +#define getsid(Mp) (Mp) +#define HAVE_GETUSERATTR 1 +#define USE_TC 1 +#define USE_UTENT 1 +#else + +#if defined V386 +typedef int mode_t; +#define getdtablesize() OPEN_MAX +#define setsid() getpid() +#define getsid(Mp) (Mp) +#define setgroups(x, y) 0 +#include +#include +#define USE_IOCTL 1 +#define USE_TC 1 +#else + +#if defined S81 +#include +#include +typedef int mode_t; +#define setsid() getpid() +#define getsid(Mp) (Mp) +#define USE_IOCTL 1 +#define USE_TC 0 +#define USE_OLD_UTENT 1 +#else + +#if defined(NETBSD) +#include +#include +#include +#include +#include +#define setsid() getpid() +#define getsid(Mp) (Mp) +#define USE_IOCTL 1 +#define USE_OLD_UTENT 1 +#define PATH_SU "/usr/ucb/su" +#define UTMP_PATH "/var/run/utmp" +#else + +#if defined(FREEBSD) +#include +#include +#include +#include +#include +#define setsid() getpid() +#define getsid(Mp) (Mp) +#define USE_IOCTL 1 +#define USE_OLD_UTENT 1 +#define PATH_SU "/usr/ucb/su" +#else + +#include +#endif /* NETBSD */ +#endif /* 386bsd or equiv */ +#endif /* sequent */ +#endif /* intel v386 */ +#endif /* find termios */ +#endif /* find any term stuff */ + + +#ifdef SUNOS +#include +#include +#define setsid() getpid() +#define getsid(Mp) (Mp) +#endif + +#if ! defined V386 +#include +#endif + +#ifdef IBMR2 +#include +#include +#endif /* IBMR2 */ + +#include "main.h" + + +#define TTYMODE 0600 + +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#ifndef NGROUPS_MAX +#define NGROUPS_MAX 8 +#endif + +#if !defined(UTMP_FILE) +#if defined(_PATH_UTMP) +#define UTMP_FILE _PATH_UTMP +#else +#define UTMP_FILE "/etc/utmp" +#endif +#endif + +#if !defined(PATH_SU) +#define PATH_SU "/bin/su" +#endif + +/* + * Global variables + */ + +#ifndef lint +char *rcsid = "$Id: autologin.c,v 1.22 93/09/04 21:48:41 ksb Exp $"; +#endif /* not lint */ +char *progname; +gid_t awGrps[NGROUPS_MAX]; +int iGrps = 0; + +/* + * External variables + */ + +extern int optind; +extern char *optarg; + +void make_utmp(); +void usage(); + +int +Process() +{ + register int c; + int iErrs = 0; + int i, iNewGrp; + gid_t wGid; + uid_t wUid; + char *pcCmd = (char *)0, + *pcDevTty = (char *)0; + char *pcTmp; +#ifdef IBMR2 + char *pcGrps; +#endif /* IBMR2 */ + struct passwd *pwd; + struct stat st; +#if USE_IOCTL + auto struct sgttyb n_sty; +#if USE_TC + auto struct tc n_tchars; +#else + auto struct tchars n_tchars; +#endif +#if HAVE_JOBS + auto struct ltchars n_ltchars; +#endif +#else + struct termios n_tio; +#endif + + + if ((char *)0 != pcCommand) { + if ((char *)0 == (pcCmd = (char *)malloc(strlen(pcCommand) + 4))) { + (void) fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + (void)strcpy(pcCmd, "-c "); + (void)strcat(pcCmd, pcCommand); + } + + if ( (char *)0 != pcGroup ) { + iErrs += addgroup(pcGroup); + } + + if ( (char *)0 == pcLogin ) { + static char acLogin[17]; + if ((struct passwd *)0 == (pwd = getpwuid(geteuid()))) { + (void) fprintf(stderr, "%s: %d: uid unknown\n", progname, geteuid()); + exit(1); + /* NOTREACHED */ + } + pcLogin = strcpy(acLogin, pwd->pw_name); + } else if ((struct passwd *)0 == (pwd = getpwnam(pcLogin))) { + (void) fprintf(stderr, "%s: %s: login name unknown\n", progname, pcLogin); + exit(1); + /* NOTREACHED */ + } + wUid = pwd->pw_uid; + wGid = pwd->pw_gid; +#ifdef HAVE_GETUSERATTR + /* getuserattr() returns a funny list of groups: + * "grp1\0grp2\0grp3\0\0" + */ + if (0 == getuserattr(pcLogin, S_SUGROUPS, &pcGrps, SEC_LIST)) { + while ('\000' != *pcGrps) { + /* ignore "ALL" and any group beginning with '!' */ + if ('!' == *pcGrps || 0 != strcmp(pcGrps, "ALL")) { + iErrs += addgroup(pcGrps); + } + pcGrps = pcGrps + strlen(pcGrps) + 1; + } + } +#endif /* HAVE_GETUSERATTR */ + + if ((char *)0 != pcTty) { + if ( '/' == *pcTty ) { + pcDevTty = pcTty; + } else { + if ( (char *)0 == (pcDevTty = (char *)malloc(strlen(pcTty)+5+1) ) ) { + (void) fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno)); + exit(1); + } + sprintf(pcDevTty, "/dev/%s", pcTty); + } + + + if (0 != stat(pcDevTty, &st)) { + (void) fprintf(stderr, "%s: Can't stat %s: %s\n", progname, pcDevTty, strerror(errno)); + ++iErrs; +#ifdef IBMR2 + } else if (VCHR != st.st_type && VMPC != st.st_type) { + (void) fprintf(stderr, "%s: %s is not a character device\n", progname, pcDevTty); + ++iErrs; +#endif + } + } else { + pcDevTty = (char *)0; + } + + if (iErrs) { + usage(); + exit(1); + /* NOTREACHED */ + } + if (0 != geteuid()) { + (void) fprintf(stderr, "%s: Must be root!!!\n", progname); + exit(1); + /* NOTREACHED */ + } + if (iGrps && 0 < setgroups(iGrps, awGrps)) { + (void) fprintf(stderr, "%s: Can't setgroups(): %s\n", progname, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + + /* Close open files + */ + for (i = (char *)0 == pcTty ? 3 : 0; i < getdtablesize(); ++i) { + (void) close(i); + } + + /* Make us a session leader so that when we open /dev/tty + * it will become our controlling terminal. + */ + if (-1 == (iNewGrp = getsid(getpid()))) { + if (-1 == (iNewGrp = setsid())) { + (void) fprintf(stderr, "%s: setsid: %d: %s\n", progname, iNewGrp, strerror(errno)); + iNewGrp = getpid(); + } + } + + /* Open the TTY for stdin, stdout and stderr + */ + if ((char *)0 != pcDevTty) { +#ifdef TIOCNOTTY + if (-1 != (i = open("/dev/tty", 2, 0))) { + if ( ioctl(i, TIOCNOTTY, (char *)0) ) + (void) fprintf(stderr, "%s: ioctl(%d, TIOCNOTTY, (char *)0): %s\n", progname, i, strerror(errno)); + (void) close(i); + } +#endif + if (0 != open(pcDevTty, O_RDWR, 0666)) { + exit(1); + /* NOTREACHED */ + } + dup(0); + dup(0); + } + + /* put the tty in out process group + */ +#if ! (EPIX || SUN5) +#if USE_TC + if (-1 >= (i = tcgetpgrp(0))){ + (void) fprintf(stderr, "%s: tcgetpgrp: %s\n", progname, strerror(errno)); + } +#endif +#if USE_SETPGRP + if (-1 != i && setpgrp(0, i) ){ + (void) fprintf(stderr, "%s: setpgrp: %s, i = %d\n", progname, strerror(errno), i); + } +#endif + +#if USE_TC + if (tcsetpgrp(0, iNewGrp)){ + (void) fprintf(stderr, "%s: tcsetpgrp: %s\n", progname, strerror(errno)); + } +#endif +#if USE_SETPGRP + if (-1 != iNewGrp && setpgrp(0, iNewGrp)){ + (void) fprintf(stderr, "%s: setpgrp: %s, iNewGrp = %d\n", progname, strerror(errno), iNewGrp); + } +#endif + +#endif + + /* put the tty in the correct mode + */ +#if USE_IOCTL + if (0 != ioctl(0, TIOCGETP, (char *)&n_sty)) { + fprintf(stderr, "%s: iotcl: getp: %s\n", progname, strerror(errno)); + exit(10); + } +#if USE_TC + n_sty.sg_flags &= ~(O_CBREAK); + n_sty.sg_flags |= (O_CRMOD|O_ECHO); +#else + n_sty.sg_flags &= ~(CBREAK); + n_sty.sg_flags |= (CRMOD|ECHO); +#endif + n_sty.sg_kill = '\025'; /* ^U */ + n_sty.sg_erase = '\010'; /* ^H */ + if (0 != ioctl(0, TIOCSETP, (char *)&n_sty)) { + fprintf(stderr, "%s: iotcl: setp: %s\n", progname, strerror(errno)); + exit(10); + } + + /* stty undef all tty chars + */ +#if 0 + if (-1 == ioctl(0, TIOCGETC, (char *)&n_tchars)) { + fprintf(stderr, "%s: ioctl: getc: %s\n", progname, strerror(errno)); + return; + } + n_tchars.t_intrc = -1; + n_tchars.t_quitc = -1; + if (-1 == ioctl(0, TIOCSETC, (char *)&n_tchars)) { + fprintf(stderr, "%s: ioctl: setc: %s\n", progname, strerror(errno)); + return; + } +#endif +#if HAVE_JOBS + if (-1 == ioctl(0, TIOCGLTC, (char *)&n_ltchars)) { + fprintf(stderr, "%s: ioctl: gltc: %s\n", progname, strerror(errno)); + return; + } + 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)) { + fprintf(stderr, "%s: ioctl: sltc: %s\n", progname, strerror(errno)); + return; + } +#endif +#else /* not using ioctl, using POSIX or sun stuff */ +#if USE_TC + if (0 != tcgetattr(0, &n_tio)) { + (void) fprintf(stderr, "%s: tcgetattr: %s\n", progname, strerror(errno)); + exit(1); + /* NOTREACHED */ + } +#else + if (0 != ioctl(0, TCGETS, &n_tio)) { + (void) fprintf(stderr, "%s: iotcl: TCGETS: %s\n", progname, strerror(errno)); + exit(1); + /* NOTREACHED */ + } +#endif + n_tio.c_iflag &= ~(IGNCR|IUCLC); + n_tio.c_iflag |= ICRNL|IXON|IXANY; + n_tio.c_oflag &= ~(OLCUC|ONOCR|ONLRET|OFILL|NLDLY|CRDLY|TABDLY|BSDLY); + n_tio.c_oflag |= OPOST|ONLCR|TAB3; + n_tio.c_lflag &= ~(XCASE|NOFLSH|ECHOK|ECHONL); + n_tio.c_lflag |= ISIG|ICANON|ECHO; + n_tio.c_cc[VEOF] = '\004'; /* ^D */ + n_tio.c_cc[VEOL] = '\000'; /* EOL */ + n_tio.c_cc[VERASE] = '\010'; /* ^H */ + n_tio.c_cc[VINTR] = '\003'; /* ^C */ + n_tio.c_cc[VKILL] = '\025'; /* ^U */ + /* MIN */ + n_tio.c_cc[VQUIT] = '\034'; /* ^\ */ + n_tio.c_cc[VSTART] = '\021'; /* ^Q */ + n_tio.c_cc[VSTOP] = '\023'; /* ^S */ + n_tio.c_cc[VSUSP] = '\032'; /* ^Z */ +#if USE_TC + if (0 != tcsetattr(0, TCSANOW, &n_tio)) { + (void) fprintf(stderr, "%s: tcsetattr: %s\n", progname, strerror(errno)); + exit(1); + /* NOTREACHED */ + } +#else + if (0 != ioctl(0, TCSETS, &n_tio)) { + (void) fprintf(stderr, "%s: ioctl: TCSETS: %s\n", progname, strerror(errno)); + exit(1); + /* NOTREACHED */ + } +#endif +#endif /* setup tty */ + + if (fMakeUtmp) { + extern char *ttyname(); + make_utmp(pcLogin, (char *)0 != pcTty ? pcTty : ttyname(0)); + } + /* Change ownership and modes on the tty. + */ + if ((char *)0 != pcDevTty) { + (void) chown(pcDevTty, wUid, wGid); + (void) chmod(pcDevTty, (mode_t) TTYMODE); + } + + if ((char *)0 != pcCmd) { + execl(PATH_SU, "su", "-", pcLogin, pcCmd, (char *)0); + } else { + execl(PATH_SU, "su", "-", pcLogin, (char *)0); + } +} + +#if NEED_PUTENV +int +putenv(pcAssign) +char *pcAssign; +{ + register char *pcEq; + + if ((char *)0 != (pcEq = strchr(pcAssign, '='))) { + *pcEq++ = '\000'; + (void)setenv(pcAssign, pcEq, 1); + *--pcEq = '='; + } else { + unsetenv(pcAssign); + } +} +#endif + +int +addgroup(pcGrp) +char *pcGrp; +{ + struct group *grp; + + grp = getgrnam(pcGrp); + if ((struct group *)0 == grp) { + (void) fprintf(stderr, "%s: Unknown group: %s\n", progname, pcGrp); + return(1); + } + if (iGrps >= NGROUPS_MAX) { + (void) fprintf(stderr, "%s: Too many groups specified with \"%s\".\n", progname, pcGrp); + return(1); + } + awGrps[iGrps++] = grp->gr_gid; + return(0); +} + + +/* install a utmp entry to show the use we know is here is here (ksb) + */ +void +make_utmp(pclogin, pctty) +char *pclogin; +char *pctty; +{ + register int iFound, iPos; + register int fdUtmp; + register char *pcDev; + register struct utmp *up; + auto struct utmp outmp, utmp; + + + if ((char *)0 == pctty) { + return; + } + + if ((fdUtmp = open(UTMP_FILE, O_RDWR, 0664)) < 0) { + return; + } + + /* create empty utmp entry + */ + (void)memset(&utmp, 0, sizeof(struct utmp)); + + /* Only the last portion of the tty is saved, unless it's + * all digits. Then back up and include the previous part + * /dev/pty/02 -> pty/02 (not just 02) + */ + if ((char *)0 != (pcDev = strrchr(pctty, '/'))) { + if (! *(pcDev + strspn(pcDev, "/0123456789"))) { + while (pcDev != pctty && *--pcDev != '/') { + } + } + if (*pcDev == '/') { + ++pcDev; + } + } else { + pcDev = pctty; + } + +#if USE_OLD_UTENT + /* look through /etc/utmp by hand (sigh) + */ + iFound = iPos = 0; + while (sizeof(utmp) == read(fdUtmp, & utmp, sizeof(utmp))) { + if (0 == strncmp(utmp.ut_line, pcDev, sizeof(utmp.ut_line))) { + ++iFound; + break; + } + iPos++; + } + (void)strncpy(utmp.ut_name, pclogin, sizeof(utmp.ut_name)); +#else +#if USE_UTENT + /* look through getutent's by pid + */ + (void)setutent(); + utmp.ut_pid = getpid(); + iFound = iPos = 0; + while ((up = getutent()) != NULL) { + if (up->ut_pid == utmp.ut_pid) { + utmp = *up; + ++iFound; + break; + } + iPos++; + } + (void)endutent(); + /* we were an initprocess, now we are a login shell + */ + utmp.ut_type = USER_PROCESS; + (void)strncpy(utmp.ut_user, pclogin, sizeof(utmp.ut_user)); + if ('\000' == utmp.ut_line[0]) { + (void)strncpy(utmp.ut_line, pcDev, sizeof(utmp.ut_line)); + } +#else + { + register struct ttyent *ty; + + /* look through ttyslots by line? + */ + (void)setttyent(); + iFound = iPos = 0; + while ((ty = getttyent()) != NULL) { + if (strcmp(ty->ty_name, pcDev) == 0) { + ++iFound; + break; + } + iPos++; + } + /* fill in utmp from ty ZZZ */ + (void)endttyent(); + } + (void)strncpy(utmp.ut_line, pcDev, sizeof(utmp.ut_line)); + (void)strncpy(utmp.ut_name, pclogin, sizeof(utmp.ut_name)); + (void)strncpy(utmp.ut_host, "(autologin)", sizeof(utmp.ut_host)); +#endif +#endif + utmp.ut_time = time((time_t *) 0); + + if (0 == iFound) { + fprintf(stderr, "%s: %s: no ttyslot\n", progname, pctty); + } else if (-1 == lseek(fdUtmp, (off_t)(iPos*sizeof(utmp)), 0)) { + fprintf(stderr, "%s: lseek: %s\n", progname, strerror(errno)); + } else { + (void)write(fdUtmp, (char *)&utmp, sizeof(utmp)); + } + (void)close(fdUtmp); +} + + +void +usage() +{ + char *u_pch; + int u_loop; + + for (u_loop = 0; (char *)0 != (u_pch = au_terse[u_loop]); ++u_loop) { + fprintf(stdout, "%s: usage%s\n", progname, u_pch); + } + for (u_loop = 0; (char *)0 != (u_pch = u_help[u_loop]); ++u_loop) { + fprintf(stdout, "%s\n", u_pch); + } + +} diff --git a/autologin/autologin.m b/autologin/autologin.m new file mode 100644 index 0000000..89f2da9 --- /dev/null +++ b/autologin/autologin.m @@ -0,0 +1,57 @@ +# mkcmd parser for autologin program +%% +static char *rcsid = + "$Id: autologin.m,v 1.2 92/07/28 13:18:34 ksb Exp $"; +%% + +integer variable "iErrs" { + init "0" +} + +char* 'c' { + named "pcCommand" + param "cmd" + init '(char *)0' + help "command to run" +} + +function 'e' { + named "putenv" + param "env=value" + update "if (%n(%N) != 0) { (void) fprintf(stderr, \"%%s: putenv(\\\"%%s\\\"): failed\\n\", %b, %N);exit(1);}" + help "environment variable to set" +} + +char* 'g' { + named "pcGroup" + param "group" + init '(char *)0' + help "initial group" +} + +char* 'l' { + named "pcLogin" + param "login" + init '(char *)0' + help "login name" +} + +char* 't' { + named "pcTty" + param "tty" + init '(char *)0' + help "attach to this terminal" +} + +boolean 'u' { + named "fMakeUtmp" + init "1" + update "%run = 0;" + help "do no make utmp entry" +} + +exit { + named "Process" + update "%n();" + aborts "exit(iErrs);" +} diff --git a/autologin/autologin.man b/autologin/autologin.man new file mode 100644 index 0000000..3451838 --- /dev/null +++ b/autologin/autologin.man @@ -0,0 +1,141 @@ +.\" $Id: autologin.man,v 1.3 93/03/16 16:41:45 ksb Exp $ +.TH AUTOLOGIN 8L PUCC +.SH NAME +autologin \- create an automatic login session from /etc/inittab +.SH SYNOPSIS +.B /usr/local/etc/autologin +[ +.B \-u +] [ +.B \-c +.I command +] [ +.B \-e +.IB env = val +] [ +.B \-g +.I group +] [ +.B \-l +.I login +] [ +.B \-t +.I tty +] +.SH DESCRIPTION +.I Autologin +creates a login session for +.I login +by running an +.RB ` "su \- +.IR login ' +on the specified device +.RI ( tty ). +If a +.I command +is given, that command is executed via +.RB ` "su \- +.IB login " \-c +.IR command .' +.PP +.I Autologin +also changes the ownership of the tty port to the user and sets the +mode to 0600. +.PP +On AIX, +.I autologin +uses +.IR getuserattr ( 3 ) +to determine which groups are required to su to +.I login +and sets those groups for the process before executing the +.IR su ( 1 ) +command. +.SH OPTIONS +.TP \w'command'u+4 +.BI \-c command +Execute the command +.IR command . +The default action is to create a login shell. +.TP +.BI \-e env = val +Add the evironment variable assignment +.IB env = val +to the environment. +.TP +.BI \-g group +Add +.I group +to current process group set before running +.IR su ( 1 ). +This option probably isn't necessary since the group set should be +properly handled through the use of +.IR getuserattr ( 3 ). +.TP +.BI \-l login +Create the login process for the user +.IR login . +If none is given the effective uid is used. +.TP +.BI \-t tty +.I tty +is the name of the character-special file that corresponds to the terminal +to be logged in. +If none is given the current controlling terminal is used. +.TP +.B \-u +Don't create a utmp entry. Normally, an entry is written to +.I /etc/utmp +to maintain a record of users logged into the system. +.SH EXAMPLES +Adding the following line to +.I /etc/inittab +on an AIX machine establishes a root login on the console terminal +.RI ( /dev/tty0 ) +with any error messages directed to +.IR /dev/console : +.br +.na + cons2:2:respawn:/usr/local/etc/autologin \-t/dev/tty0 \-lroot > /dev/console 2>&1 +.ad +.PP +Adding the following line to +.I /etc/inittab +on an AIX machine causes ssinfo to be logged in on +.I /dev/tty10 +with the +.B TERM +environment variable set to +.IR reg20 : +.br +.na + ss10:2:respawn:/usr/local/etc/autologin \-e TERM=reg20 \-t/dev/tty10 \-lssinfo +.ad +.PP +Adding the following line to \fI/etc/ttytab\fP on a Sun 4.1.\fIx\fP +machine establishes a root login on the console device: +.na + console "/usr/local/etc/autologin \-lroot \-t" xterm on local secure +.ad +Note that \fIinit\fP provides the \fItty\fP argument on the end of the command. +.SH FILES +/bin/su +.br +/etc/inittab +.br +/etc/passwd +.br +/etc/utmp +.SH "SEE ALSO" +su(1), +getuserattr(3), +inittab(5), +init(8). +.SH AUTHOR +Jeff W\. Stewart \- Purdue University Computing Center +.SH BUGS +Doesn't add entries to /usr/adm/wtmp?? +.br +Doesn't add utmp entry unless it's been setup by init(8). +.br +Only runs on SUN4, EPIX, SUN3, IBMR2 (currently). diff --git a/autologin/main.c b/autologin/main.c new file mode 100644 index 0000000..53b5f87 --- /dev/null +++ b/autologin/main.c @@ -0,0 +1,354 @@ +/* + * machine generated cmd line parser + * built by mkcmd version 7.6 Gamma + */ + +#include +#include +#include + +extern int errno; +extern char *malloc(), *calloc(), *realloc(); + +#define ENVOPT 0 +#define GETARG 0 +#define GETOPT 1 +/* from std_help.m */ +/* from std_version.m */ +/* from autologin.m */ +/* $Id: T.c,v 7.2 94/07/11 00:42:06 ksb Exp $ + * literal text included from a tempate + * based on Keith Bostic's getopt in comp.sources.unix volume1 + * modified for mkcmd use.... by ksb@cc.purdue.edu (Kevin Braunsdorf) + */ + +#if GETOPT || GETARG +/* IBMR2 (AIX in the real world) defines + * optind and optarg in and confuses the hell out + * of the C compiler. So we use those externs. I guess we will + * have to stop using the old names. -- ksb + */ +#ifdef _AIX +#include +#else +static int + optind = 1; /* index into parent argv vector */ +static char + *optarg; /* argument associated with option */ +#endif +#endif /* only if we use them */ + +#if ENVOPT +/* breakargs - break a string into a string vector for execv. + * + * Note, when done with the vector, merely "free" the vector. + * Written by Stephen Uitti, PUCC, Nov '85 for the new version + * of "popen" - "nshpopen", that doesn't use a shell. + * (used here for the as filters, a newer option). + * + * breakargs is copyright (C) Purdue University, 1985 + * + * Permission is hereby given for its free reproduction and + * modification for All purposes. + * This notice and all embedded copyright notices be retained. + */ + +/* this trys to emulate shell quoting, but I doubt it does a good job (ksb) + * [[ but not substitution -- that would be silly ]] + */ +static char * +u_mynext(u_pcScan, u_pcDest) +register char *u_pcScan, *u_pcDest; +{ + register int u_fQuote; + + for (u_fQuote = 0; *u_pcScan != '\000' && (u_fQuote||(*u_pcScan != ' ' && *u_pcScan != '\t')); ++u_pcScan) { + switch (u_fQuote) { + default: + case 0: + if ('"' == *u_pcScan) { + u_fQuote = 1; + continue; + } else if ('\'' == *u_pcScan) { + u_fQuote = 2; + continue; + } + break; + case 1: + if ('"' == *u_pcScan) { + u_fQuote = 0; + continue; + } + break; + case 2: + if ('\'' == *u_pcScan) { + u_fQuote = 0; + continue; + } + break; + } + if ((char*)0 != u_pcDest) { + *u_pcDest++ = *u_pcScan; + } + } + if ((char*)0 != u_pcDest) { + *u_pcDest = '\000'; + } + return u_pcScan; +} + +/* given an envirionment variable insert it in the option list (ksb) + * (exploded with the above routine) + */ +static int +u_envopt(cmd, pargc, pargv) +char *cmd, *(**pargv); +int *pargc; +{ + register char *p; /* tmp */ + register char **v; /* vector of commands returned */ + register unsigned sum; /* bytes for malloc */ + register int i, j; /* number of args */ + register char *s; /* save old position */ + + while (*cmd == ' ' || *cmd == '\t') + cmd++; + p = cmd; /* no leading spaces */ + i = 1 + *pargc; + sum = sizeof(char *) * i; + while (*p != '\000') { /* space for argv[]; */ + ++i; + s = p; + p = u_mynext(p, (char *)0); + sum += sizeof(char *) + 1 + (unsigned)(p - s); + while (*p == ' ' || *p == '\t') + p++; + } + ++i; + /* vector starts at v, copy of string follows NULL pointer + * the extra 7 bytes on the end allow use to be alligned + */ + v = (char **)malloc(sum+sizeof(char *)+7); + if (v == NULL) + return 0; + p = (char *)v + i * sizeof(char *); /* after NULL pointer */ + i = 0; /* word count, vector index */ + v[i++] = (*pargv)[0]; + while (*cmd != '\000') { + v[i++] = p; + cmd = u_mynext(cmd, p); + p += strlen(p)+1; + while (*cmd == ' ' || *cmd == '\t') + ++cmd; + } + for (j = 1; j < *pargc; ++j) + v[i++] = (*pargv)[j]; + v[i] = NULL; + *pargv = v; + *pargc = i; + return i; +} +#endif /* u_envopt called */ + +#if GETARG +/* + * return each non-option argument one at a time, EOF for end of list + */ +static int +u_getarg(nargc, nargv) +int nargc; +char **nargv; +{ + if (nargc <= optind) { + optarg = (char *) 0; + return EOF; + } + optarg = nargv[optind++]; + return 0; +} +#endif /* u_getarg called */ + + +#if GETOPT +static int + optopt; /* character checked for validity */ + +/* get option letter from argument vector, also does -number correctly + * for nice, xargs, and stuff (these extras by ksb) + * does +arg if you give a last argument of "+", else give (char *)0 + */ +static int +u_getopt(nargc, nargv, ostr, estr) +int nargc; +char **nargv, *ostr, *estr; +{ + register char *oli; /* option letter list index */ + static char EMSG[] = ""; /* just a null place */ + static char *place = EMSG; /* option letter processing */ + + if ('\000' == *place) { /* update scanning pointer */ + if (optind >= nargc) + return EOF; + if (nargv[optind][0] != '-') { + register int iLen; + if ((char *)0 != estr && 0 == strncmp(estr, nargv[optind], iLen = strlen(estr))) { + optarg = nargv[optind++]+iLen; + return '+'; + } + return EOF; + } + place = nargv[optind]; + if ('\000' == *++place) /* "-" (stdin) */ + return EOF; + if (*place == '-' && '\000' == place[1]) { + /* found "--" */ + ++optind; + return EOF; + } + } /* option letter okay? */ + /* if we find the letter, (not a `:') + * or a digit to match a # in the list + */ + if ((optopt = *place++) == ':' || + ((char *)0 == (oli = strchr(ostr,optopt)) && + (!(isdigit(optopt)||'-'==optopt) || (char *)0 == (oli = strchr(ostr, '#'))))) { + if(!*place) ++optind; + return('?'); + } + if ('#' == *oli) { /* accept as -digits */ + optarg = place -1; + ++optind; + place = EMSG; + return '#'; + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if ('\000' == *place) + ++optind; + } else { /* need an argument */ + if (*place) { /* no white space */ + optarg = place; + } else if (nargc <= ++optind) { /* no arg!! */ + place = EMSG; + return '*'; + } else { + optarg = nargv[optind]; /* white space */ + } + place = EMSG; + ++optind; + } + return optopt; /* dump back option letter */ +} +#endif /* u_getopt called */ +#undef ENVOPT +#undef GETARG +#undef GETOPT + +char + *progname = "$Id$", + *au_terse[] = { + " [-u] [-c cmd] [-e env=value] [-g group] [-l login] [-t tty]", + " -h", + " -V", + (char *)0 + }, + *u_help[] = { + "c cmd command to run", + "e env=value environment variable to set", + "g group initial group", + "h print this help message", + "l login login name", + "t tty attach to this terminal", + "u do no make utmp entry", + "V show version information", + (char *)0 + }, + *pcCommand = (char *)0, + *pcGroup = (char *)0, + *pcLogin = (char *)0, + *pcTty = (char *)0; +int + fMakeUtmp = 1, + iErrs = 0; + +#ifndef u_terse +#define u_terse (au_terse[0]) +#endif +/* from std_help.m */ +/* from std_version.m */ +/* from autologin.m */ + +static char *rcsid = + "$Id: autologin.m,v 1.2 92/07/28 13:18:34 ksb Exp $"; + +/* + * parser + */ +int +main(argc, argv) +int argc; +char **argv; +{ + static char + sbOpt[] = "c:e:g:hl:t:uV", + *u_pch = (char *)0; + static int + u_loop = 0; + register int u_curopt; + extern int atoi(); + + progname = strrchr(argv[0], '/'); + if ((char *)0 == progname) + progname = argv[0]; + else + ++progname; + while (EOF != (u_curopt = u_getopt(argc, argv, sbOpt, (char *)0))) { + switch (u_curopt) { + case '*': + fprintf(stderr, "%s: option `-%c\' needs a parameter\n", progname, optopt); + exit(1); + case '?': + fprintf(stderr, "%s: unknown option `-%c\', use `-h\' for help\n", progname, optopt); + exit(1); + case 'c': + pcCommand = optarg; + continue; + case 'e': + if (putenv(optarg) != 0) { + (void) fprintf(stderr, "%s: putenv(\"%s\"): failed\n", progname, optarg); + exit(1); + } + continue; + case 'g': + pcGroup = optarg; + continue; + case 'h': + for (u_loop = 0; (char *)0 != (u_pch = au_terse[u_loop]); ++u_loop) { + if ('\000' == *u_pch) { + fprintf(stdout, "%s: with no parameters\n", progname); + continue; + } + fprintf(stdout, "%s: usage%s\n", progname, u_pch); + } + for (u_loop = 0; (char *)0 != (u_pch = u_help[u_loop]); ++u_loop) { + fprintf(stdout, "%s\n", u_pch); + } + exit(0); + case 'l': + pcLogin = optarg; + continue; + case 't': + pcTty = optarg; + continue; + case 'u': + fMakeUtmp = 0; + continue; + case 'V': + printf("%s: %s\n", progname, rcsid); + exit(0); + } + break; + } + Process(); + exit(iErrs); +} diff --git a/autologin/main.h b/autologin/main.h new file mode 100644 index 0000000..b97aa35 --- /dev/null +++ b/autologin/main.h @@ -0,0 +1,15 @@ +/* + * parse options + */ + +extern char *progname, *au_terse[4], *u_help[9]; +#ifndef u_terse +#define u_terse (au_terse[0]) +#endif +extern int main(); +extern int fMakeUtmp, iErrs; +extern char *pcCommand, *pcGroup, *pcLogin, *pcTty; +/* from std_help.m */ +/* from std_version.m */ +/* from autologin.m */ + diff --git a/conserver.cf/INSTALL b/conserver.cf/INSTALL new file mode 100644 index 0000000..181ce9f --- /dev/null +++ b/conserver.cf/INSTALL @@ -0,0 +1,26 @@ +# $Id: INSTALL,v 4.1 91/06/19 14:20:54 ksb Exp $ + +Prep: + + Start in the conserver directory. + + Now read conserver.cf.5l (if you have mk(1L) installed just mk it). + Run: + $ tbl conserver.cf.5l |nroff -man |${PAGER-more} + + Now edit dummy.cf and follow the instructions there. + [If you are just shopping stop here.] + + Now edit conserver.cf and put your real hosts in there. + + Edit the Makefile and change LIB. + + +Compile: + + None. + + +Install: + + Make install. diff --git a/conserver.cf/Makefile b/conserver.cf/Makefile new file mode 100644 index 0000000..138b926 --- /dev/null +++ b/conserver.cf/Makefile @@ -0,0 +1,59 @@ +# $Id: Make.host,v 4.3 92/07/10 15:57:32 dru Exp $ +# +# Makefile for conserver data base +# + +# if you edit LIB below you have to change cons.hs default config define. +PROG= conserver.cf +LIB= ${DESTDIR}/usr/local/lib +DOC= ${DESTDIR}/usr/man + +SRCs= conserver.cf +MAN= conserver.cf.5l +OTHER= README +SOURCE= Makefile ${OTHER} ${MAN} ${SRCl} ${SRCs} + +all: ${SRCl} ${PROG} + +${PROG}: ${SRCs} + +clean: FRC + rm -f Makefile.bak a.out core errs lint.out tags + +deinstall: ${MAN} ${DOC} FRC + install -R ${LIB}/${PROG} + mkcat -r${DOC} -D ${MAN} + +depend: FRC + +dirs: ${LIB} ${DOC} + +install: all dirs FRC + install -c ${PROG} ${LIB}/${PROG} + +lint: FRC + +mkcat: ${MAN} ${DOC} FRC + mkcat -r${DOC} ${MAN} + +print: source FRC + lpr -J"${PROG} source" ${SOURCE} + +source: ${SOURCE} + +spotless: clean + rcsclean ${SOURCE} + +tags: FRC + +/ ${LIB} ${LIB}: + install -dr $@ + +${SOURCE}: + co -q $@ + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +# *** Do not add anything here - It will go away. *** diff --git a/conserver.cf/README b/conserver.cf/README new file mode 100644 index 0000000..d5f8931 --- /dev/null +++ b/conserver.cf/README @@ -0,0 +1,16 @@ +# $Id: README,v 4.1 91/06/19 14:21:06 ksb Exp $ + +This configuration file has been extended from the Ohio State version. We +allow parity and baud to be set, as well as more than one console server +machine to be in play at a time. We have too many console servers to use +just a single Sun3... :-). + + +We also allow another section for trusted hosts. We allow our operators root +access by physical access to a workstation. + + +-- +"So I try to say `Goodbye, my friend.' + I'd like to leave you with something more..." +kayessbee, Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb diff --git a/conserver.cf/conserver.cf b/conserver.cf/conserver.cf new file mode 100644 index 0000000..218b273 --- /dev/null +++ b/conserver.cf/conserver.cf @@ -0,0 +1,76 @@ +# conserver config file +# +# $Id: conserver.cf,v 4.20 94/05/22 11:17:26 ksb Exp $ +# +# list of consoles we serve +# name : tty[@host] : baud[parity] : device : group +# our local console +console:|@console.cc.purdue.edu:9600p:/usr/adm/consoles/console:0 +nextwatch:|@console.cc.purdue.edu:9600p:/usr/adm/consoles/nextwatch:0 +# real machine +speedy:/dev/ttyC12@console.cc.purdue.edu:9600s:/usr/adm/consoles/speedy:1 +nis35:/dev/ttyC13@console.cc.purdue.edu:9600s:/usr/adm/consoles/nis35:1 +sun3watch:/dev/ttyC40@console.cc.purdue.edu:9600p:/usr/adm/consoles/sun3watch:1 +keep:/dev/ttyC29@console.cc.purdue.edu:9600s:/usr/adm/consoles/keep:1 +dart:/dev/ttyC32@console.cc.purdue.edu:9600s:/usr/adm/consoles/dart:1 +lively:/dev/ttyC10@console.cc.purdue.edu:9600s:/usr/adm/consoles/lively:2 +sentinel:/dev/ttyC11@console.cc.purdue.edu:9600s:/usr/adm/consoles/sentinel:2 +ipscgate:/dev/ttyC26@console.cc.purdue.edu:9600e:/usr/adm/consoles/ipscgate:2 +snap.stat:/dev/ttyC27@console.cc.purdue.edu:9600s:/usr/adm/consoles/snap.stat:2 +b.stat:/dev/ttyC33@console.cc.purdue.edu:9600s:/usr/adm/consoles/b.stat:2 +expert:/dev/ttyC14@console.cc.purdue.edu:9600e:/usr/adm/consoles/expert:3 +quick:/dev/ttyC15@console.cc.purdue.edu:9600s:/usr/adm/consoles/quick:3 +helios:/dev/ttyC31@console.cc.purdue.edu:9600s:/usr/adm/consoles/helios:3 +probe:/dev/ttyC34@console.cc.purdue.edu:9600s:/usr/adm/consoles/probe:3 +mace:/dev/ttyC8@console.cc.purdue.edu:4800s:/usr/adm/consoles/mace:4 +sage:/dev/ttyC9@console.cc.purdue.edu:9600e:/usr/adm/consoles/sage:4 +flash:/dev/ttyC24@console.cc.purdue.edu:9600s:/usr/adm/consoles/flash:4 +labwatch:/dev/ttyC25@console.cc.purdue.edu:9600s:/usr/adm/consoles/labwatch:4 +dash:/dev/ttyC35@console.cc.purdue.edu:9600s:/usr/adm/consoles/dash:4 +icd92:/dev/ttyC4@console.cc.purdue.edu:9600s:/usr/adm/consoles/icd92:5 +pop.stat:/dev/ttyC5@console.cc.purdue.edu:9600s:/usr/adm/consoles/pop.stat:5 +icd94:/dev/ttyC20@console.cc.purdue.edu:9600s:/usr/adm/consoles/icd94:5 +oasis:/dev/ttyC21@console.cc.purdue.edu:9600s:/usr/adm/consoles/oasis:5 +deft:/dev/ttyC36@console.cc.purdue.edu:9600s:/usr/adm/consoles/deft:5 +mentor:/dev/ttyC2@console.cc.purdue.edu:9600e:/usr/adm/consoles/mentor:6 +icd84:/dev/ttyC3@console.cc.purdue.edu:9600s:/usr/adm/consoles/icd84:6 +franklin:/dev/ttyC18@console.cc.purdue.edu:9600s:/usr/adm/consoles/franklin:6 +icd82:/dev/ttyC19@console.cc.purdue.edu:9600s:/usr/adm/consoles/icd82:6 +prism:/dev/ttyC38@console.cc.purdue.edu:9600s:/usr/adm/consoles/prism:6 +rapid:/dev/ttyC6@console.cc.purdue.edu:9600s:/usr/adm/consoles/rapid:7 +tyro:/dev/ttyC7@console.cc.purdue.edu:9600e:/usr/adm/consoles/tyro:7 +staff:/dev/ttyC22@console.cc.purdue.edu:9600s:/usr/adm/consoles/staff:7 +swift:/dev/ttyC23@console.cc.purdue.edu:9600s:/usr/adm/consoles/swift:7 +quest:/dev/ttyC37@console.cc.purdue.edu:9600s:/usr/adm/consoles/quest:7 +icd96:/dev/ttyC0@console.cc.purdue.edu:9600s:/usr/adm/consoles/icd96:8 +fleet:/dev/ttyC1@console.cc.purdue.edu:9600s:/usr/adm/consoles/fleet:8 +feserve:/dev/ttyC16@console.cc.purdue.edu:9600s:/usr/adm/consoles/feserve:8 +curator:/dev/ttyC17@console.cc.purdue.edu:9600s:/usr/adm/consoles/curator:8 +soltest:/dev/ttyC39@console.cc.purdue.edu:9600s:/usr/adm/consoles/soltest:8 +mozo:/dev/ttyC41@console.cc.purdue.edu:9600s:/usr/adm/consoles/mozo:9 +notus:/dev/ttyC42@console.cc.purdue.edu:9600s:/usr/adm/consoles/notus: +eurus:/dev/ttyC43@console.cc.purdue.edu:9600s:/usr/adm/consoles/eurus: +boreas:/dev/ttyC44@console.cc.purdue.edu:9600s:/usr/adm/consoles/boreas: +zephyrus:/dev/ttyC45@console.cc.purdue.edu:9600s:/usr/adm/consoles/zephyrus: +fegrader:/dev/ttyC46@console.cc.purdue.edu:9600s:/usr/adm/consoles/fegrader: +galaxy:/dev/ttyC47@console.cc.purdue.edu:9600s:/usr/adm/consoles/galaxy: +# ups monitor connection (ksb -- testing) +ups:/dev/ttyb@console.cc.purdue.edu:9600e:/usr/adm/consoles/ups:10 +# VM Group consoles +tag:/dev/ttyC30@console.cc.purdue.edu:9600s:/usr/adm/consoles/tag:11:R85ONdmDqSwQ6 +# All remote consoles +# on staff.cc.purdue.edu +extra:/dev/ttyb@staff.cc.purdue.edu:9600s:/usr/adm/extra.log:0 +vet:/dev/tty0d@staff.cc.purdue.edu:9600s:/usr/adm/vet.log:1:5m6N/RqJcay6I +bull:/dev/tty0e@staff.cc.purdue.edu:9600s:/usr/adm/bull.log: +serval:/dev/tty0f@staff.cc.purdue.edu:9600s:/usr/adm/serval.log: +# virtual consoles on remote hosts +tbtape:|su - informix@oasis.cc.purdue.edu:9600p:/usr/adm/tbtape.log:0 +# so we can write on mace.cc +wmace:|/bin/csh -i@mace.cc.purdue.edu:9600p:/usr/adm/mace.log:0 +%% +# list of clients we allow +# type machines +trusted: console.cc.purdue.edu +allowed: cc.purdue.edu stat.purdue.edu +allowed: 128.210.10.8 128.210.33.1 128.210.7.49 127.0.0.1 diff --git a/conserver.cf/conserver.cf.5l b/conserver.cf/conserver.cf.5l new file mode 100644 index 0000000..6ca16db --- /dev/null +++ b/conserver.cf/conserver.cf.5l @@ -0,0 +1,96 @@ +.\" $Id: conserver.cf.5l,v 1.4 93/02/11 13:06:32 ksb Exp $ +.\" @(#)constab.5 01/06/91 OSU CIS; Thomas A. Fine +.TH CONSERVER.CF 5L "15 February 1991" "OSU/CIS" +.SH NAME +conserver.cf \- table of server console terminals used by conserver(8L) +.SH SYNOPSIS +.B /usr/local/lib/conserver.cf +.br +\fIaccess hosts\fP +.br +\fB%%\fP +.br +\fIserver\fP:\fIdevice\fP:\fIbaud\fP:\fIlogfile\fP:\fIgroup\fP +.SH DESCRIPTION +.B Conserver.cf +is the configuration file for +.IR conserver (8L). +All lines starting with the pound sign `#' are considered comment lines. +Blank lines are ignored. +.PP +The first section of the file has lines that are separated into +six colon-separated fields: +.PP +\fIServer\fP name - this doesn't have to be the name of the server; +it is used to refer to the server when using the console program. +.PP +\fIDevice\fP file name - the full path name of the device for this server. +This may contain a remote host name as \fItty\fP@\fIhost\fP in which case +the conserver will send connections for this server to \fIhost\fP. +.PP +\fIBaud\fP 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. +.PP +\fILog\fP file name - the full path name of file where all output from +this server is logged. +.PP +\fIGroup\fP number - defines which group of servers this server is with. There +will be one process running for each group of servers in this file. +If this field is empty the conserver program will fill groups automatically. +.PP +\fIPassword\fP encrypted password - allows access to any member console in +this group. That is to say only one console in any group should set a +password. If none set a password the superuser password is taken. +.PP +This section is terminated with a `%%' 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. +Three levels of access all allowed, ``trust'', ``allow'', +and ``refuse''. +The access modifier is followed by a colon and a list of addresses or +host names. +Any complete suffix of a host name my be used to allow access for all hosts +in that subdomain. +For example `cc.purdue.edu' will allow `mentor.cc.purdue.edu' +and `mace.cc.purdue.edu', but not `pucc.purdue.edu' or `hack.purdue.edu'. +.SH LIMITS +.PP +Groups should be numbered from 0, all members of a group should be contiguous +in the file. +The current hard limits are 20 groups, with 10 members per group. +.SH EXAMPLE +# server:/dev/file:baud:/usr/adm/logfile:group_num +.br +tree:/dev/ttyj0:9600e:/tmp/treelog:0 +.br +fish:/dev/ttyj1:4800e:/tmp/fishlog:1 +.br +bird:/dev/ttyj2:4800m:/tmp/birdlog:1 +.br +solar:/dev/ttyj3:9600e:/tmp/solarlog:2 +.br +stellar:/dev/ttyj4:9600e:/tmp/stellarlog: +.br +shell:/dev/ttyj5:1200e:/tmp/shelllog:3:NLKyxm2KjHrzE +.br +tribe:/dev/ttyj6:1200e:/tmp/tribelog:4 +.br +reptile:/dev/ttyj7:1200e:/tmp/reptilelog: +.br +flower:/dev/ttyj8:1200e:/tmp/flowerlog: +.br +mentor:/dev/ttyh0@extra.cc.purdue.edu:2400e:/tmp/mentor.log: +%% +.br +# access restrictions +.br +trusted: console.cc.purdue.edu 128.210.7.90 +.br +allow: cc.purdue.edu stat.cc.purdue.edu +.sp +Notice that the console `shell' has a special password, all the others +use the superuser's password. +.SH "SEE ALSO" +console(1L), conserver(8L) diff --git a/conserver.cf/dummy.cf b/conserver.cf/dummy.cf new file mode 100644 index 0000000..0d8a47e --- /dev/null +++ b/conserver.cf/dummy.cf @@ -0,0 +1,22 @@ +# 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. +# +# list of consoles we serve +# name : tty[@host] : baud[parity] : device : group +dumb:/dev/ttya:9600p:/tmp/dummy.log:1 +login:|:9600p:/tmp/login.log:1 +%% +# list of clients we allow +# type machines +trusted: 127.0.0.1 +allowed: cc.purdue.edu diff --git a/conserver.cf/label.ps b/conserver.cf/label.ps new file mode 100644 index 0000000..6724014 --- /dev/null +++ b/conserver.cf/label.ps @@ -0,0 +1,188 @@ +%!PS-Adobe-2.0 EPSF-1.2 +%%$Id: label.ps,v 1.8 94/01/21 09:37:42 ksb Exp $ +%%Title: RJ-11 +%%Creator: A Braunsdorf +%%CreationDate: +%%For: ab +%%BoundingBox: 0 0 243 148.5 +%%EndComments + +% Add new hosts in the parens that match the port number +/hosts +[ + (icd96) % C0 + (fleet) + (mentor) + (icd84) + + (icd92) % C4 + (pop.stat) + (rapid) + (tyro) + + (mace) % C8 + (sage) + (lively) + (sentinel) + + (speedy) % C12 + (nis35) + (expert) + (quick) + + (feserve) % C16 + (curator) + (franklin) + (icd82) + + (icd94) % C20 + (oasis) + (staff) + (swift) + + (flash) % C24 + (labwatch) + (ipscgate) + (snap.stat) + + (_28) % C28 + (keep) + (tag) + (assist) +] def + +% The relative co-ords of the various RJ11 jacks +/coords +[ + % j# x y jack number, +x, +y + [ 13 0.5 1.25 ] + [ 11 1.0 1.25 ] + [ 8 1.5 1.25 ] + [ 14 0.5 0.625 ] + [ 10 1.0 0.625 ] + [ 9 1.5 0.625 ] + [ 15 0.5 0 ] + [ 12 1.0 0 ] + [ 7 2.1875 1.25 ] + [ 5 2.6875 1.25 ] + [ 3 3.1875 1.25 ] + [ 6 2.1875 0.625 ] + [ 4 2.6875 0.625 ] + [ 0 3.1875 0.625 ] + [ 2 2.6875 0 ] + [ 1 3.1875 0 ] +] def + +/str 20 string def + +% how to build an RJ11 connector diagram +/rj11 +{ + gsave + 1 150 div setlinewidth + 0 0 moveto + 1 2 div 0 lineto + 0 1 2 div rlineto + 1 2 div neg 0 rlineto + closepath + stroke + + 1 16 div 1 8 div moveto + + 0 1 4 div rlineto + 1 16 div 0 rlineto + 0 1 16 div rlineto + 3 16 div 0 rlineto + 0 2 32 div neg rlineto + 1 16 div 0 rlineto + 0 1 16 div neg rlineto + 1 16 div 0 rlineto + + 0 2 16 div neg rlineto + + 1 16 div neg 0 rlineto + 0 1 16 div neg rlineto + 1 16 div neg 0 rlineto + 0 1 16 div neg rlineto + 3 16 div neg 0 rlineto + 0 1 16 div rlineto + closepath + stroke + + 0 1 7 + { + 36 div 9 64 div add 1 16 div exch moveto + 0 1 72 div rlineto + 1 72 div 0 rlineto + 0 1 72 div neg rlineto + closepath + fill + } for + grestore + /Courier findfont 1.5 8 div scalefont setfont + 2 16 div 3 16 div moveto + str cvs + dup length 1 eq { ( )show } if show +} def + + +% Page layout stuff +72 72 scale +-90 rotate +-11 0 translate +/jack 28 def +/fudge 1 32 div def +/Courier findfont 10 72 div scalefont +setfont +0 setlinewidth + +% label the lines on the left +1 1 8 +{ + 9 div 6 mul 0.25 exch moveto + gsave fudge dup rmoveto jack str cvs show ( ) show hosts jack +get show grestore + /jack jack 1 add def + gsave 15 16 div 0 rlineto stroke grestore + 1 0 rmoveto + gsave fudge dup rmoveto jack str cvs show ( ) show hosts jack +get show grestore + /jack jack 1 add def + gsave 15 16 div 0 rlineto stroke grestore + 1 0 rmoveto + gsave fudge dup rmoveto jack str cvs show ( ) show hosts jack +get show grestore + /jack jack 1 add def + gsave 15 16 div 0 rlineto stroke grestore + 1 0 rmoveto + gsave fudge dup rmoveto jack str cvs show ( ) show hosts jack +get show grestore + /jack jack 1 add def + gsave 15 16 div 0 rlineto stroke grestore + 1 0 rmoveto + /jack jack 8 sub def +} for + +% Diddle the page and layout the RJ11s +4.5 0.75 translate +9 8 div dup scale +0 1 coords length 1 sub +{ + gsave + coords exch get + aload pop + translate + rj11 + grestore +} for +0 1 coords length 1 sub +{ + gsave + coords exch get + aload pop + 2.5 add % for the second back up 2.5 inches + translate + 16 add rj11 % ... add 16 to the RJ11 number + grestore +} for +showpage diff --git a/conserver.cf/test.cf b/conserver.cf/test.cf new file mode 100644 index 0000000..56ab590 --- /dev/null +++ b/conserver.cf/test.cf @@ -0,0 +1,23 @@ +# 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. +# +# list of consoles we serve +# name : tty[@host] : baud[parity] : device : group +DOMAINHACK= +LOGDIR=/tmp +login3:|:9600p:&:10m +test:!ts4:10002:&:1m +%% +# list of clients we allow +# type machines +allowed: 127.0.0.1 diff --git a/conserver/INSTALL b/conserver/INSTALL new file mode 100644 index 0000000..d8ffc84 --- /dev/null +++ b/conserver/INSTALL @@ -0,0 +1,114 @@ +# $Id: INSTALL,v 4.4 94/07/19 14:48:29 ksb Exp $ +# +# lpr this file, you need to read it with other stuff on the screen. +# + +Basic installation: + + First off, this stuff isn't guaranteed to work, or compile or anything. + Second, the Makefile doesn't even really do that much, because most people + with large networks don't have very normal configurations (that's a lot like + an excuse :-). Third, I assume you have the hardware set up done, and don't + need any help there (just use normal serial lines, or see Sun-serial). + + With that out of the way, let's get started. + + +Prep: + + If you are a serious kinda guy you will want to add the console service to + /etc/services, here is the line we use: + console 782/tcp conserver # console server + + Otherwise you'll have to hard code a PORT in cons.h (there are a comments + at the apropos points. + + If you do not have the PUCC ptyd daemon (and I'll bet you don't) you have + to edit the Makefile, look at the block that sets HAVE_PTYD. + + Later, on the console server you will have to add a line to /etc/rc.local, + or an atboot/cronboot job to start the console server + nice --4 /usr/local/etc/conserver >/dev/console 2>&1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "access.h" +#include "consent.h" +#include "client.h" +#include "group.h" +#include "readcfg.h" +#include "main.h" + +#if USE_STRINGS +#include +#else +#include +#endif + + +/* in the routines below (the init code) we can bomb if malloc fails (ksb) + */ +void +OutOfMem() +{ + static char acNoMem[] = ": out of memory\n"; + + write(2, progname, strlen(progname)); + write(2, acNoMem, sizeof(acNoMem)-1); + exit(45); +} + + +/* return the access type for a given host entry (ksb) + */ +char +AccType(hp) +struct hostent *hp; +{ + register int i; + register unsigned char *puc; + register char *pcName; + auto char acAddr[4*3+2]; + register int len; + + puc = (unsigned char *)hp->h_addr; + sprintf(acAddr, "%d.%d.%d.%d", puc[0], puc[1], puc[2], puc[3]); + for (i = 0; i < iAccess; ++i) { + if (isdigit(pACList[i].pcwho[0])) { + /* we could allow 128.210.7 to match all on that subnet + * here... + */ + if (0 == strcmp(acAddr, pACList[i].pcwho)) { + return pACList[i].ctrust; + } + continue; + } + pcName = hp->h_name; + len = strlen(pcName); + while (len >= pACList[i].ilen) { + if (0 == strcmp(pcName, pACList[i].pcwho)) { + return pACList[i].ctrust; + } + pcName = strchr(pcName, '.'); + if ((char *)0 == pcName) { + break; + } + ++pcName; + len = strlen(pcName); + } + } + return chDefAcc; +} + +/* we know iAccess == 0, we want to setup a nice default access list (ksb) + */ +void +SetDefAccess(hpLocal) +struct hostent *hpLocal; +{ + register char *pcWho, *pcDomain; + register unsigned char *puc; + register int iLen; + + pACList = (ACCESS *)calloc(3, sizeof(ACCESS)); + if ((ACCESS *)0 == pACList) { + OutOfMem(); + } + if ((char *)0 == (pcWho = malloc(4*3+1))) { + OutOfMem(); + } + puc = (unsigned char *)hpLocal->h_addr; + sprintf(pcWho, "%d.%d.%d.%d", puc[0], puc[1], puc[2], puc[3]); + pACList[iAccess].ctrust = 'a'; + pACList[iAccess].ilen = strlen(pcWho); + pACList[iAccess++].pcwho = pcWho; + + if ((char *)0 == (pcDomain = strchr(hpLocal->h_name, '.'))) { + return; + } + ++pcDomain; + iLen = strlen(pcDomain); + pcWho = malloc(iLen+1); + pACList[iAccess].ctrust = 'a'; + pACList[iAccess].ilen = iLen; + pACList[iAccess++].pcwho = strcpy(pcWho, pcDomain); +} + +/* thread ther list of uniq console server machines, aliases for (ksb) + * machines will screw us up + */ +REMOTE * +FindUniq(pRCAll) +register REMOTE *pRCAll; +{ + register 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 == strcmp(pRC->rhost, pRCAll->rhost)) { + return pRCAll->pRCuniq; + } + } + return pRCAll; +} + diff --git a/conserver/access.h b/conserver/access.h new file mode 100644 index 0000000..9b466cb --- /dev/null +++ b/conserver/access.h @@ -0,0 +1,48 @@ +/* + * $Id: access.h,v 5.6 1993-02-09 03:53:43-08 ldv Exp $ + * + * 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. + */ +/* + * keep track of network access and peer console servers (ksb) + */ + +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 */ +} 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 */ + char rserver[32]; /* remote server name */ + char rhost[256]; /* remote host to call to get it */ +} REMOTE; + +extern void OutOfMem(); +extern REMOTE *FindUniq(); +extern char AccType(); +extern void SetDefAccess(); diff --git a/conserver/client.c b/conserver/client.c new file mode 100644 index 0000000..0fa92c6 --- /dev/null +++ b/conserver/client.c @@ -0,0 +1,297 @@ +/* + * $Id: client.c,v 5.18 1998-11-19 14:32:20-08 bryan Exp $ + * + * 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. + */ +#ifndef lint +static char copyright[] = +"@(#) Copyright 1992 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "consent.h" +#include "client.h" + +#if USE_STRINGS +#include +#else +#include +#endif + +/* find the next guy who wants to write on the console (ksb) + */ +CLIENT * +FindWrite(pCL) +CLIENT *pCL; +{ + /* return the first guy to have the `want write' bit set + * (tell him of the promotion, too) we could look for the + * most recent or some such... I guess it doesn't matter that + * much. + */ + for (/*passed in*/; (CLIENT *)0 != pCL; pCL = pCL->pCLnext) { + if (!pCL->fwantwr) + continue; + if (!pCL->pCEto->fup || pCL->pCEto->fronly) + break; + pCL->fwantwr = 0; + pCL->fwr = 1; + if ( pCL->pCEto->nolog ) { + CSTROUT(pCL->fd, "\r\n[attached (nologging)]\r\n"); + } else { + CSTROUT(pCL->fd, "\r\n[attached]\r\n"); + } + return pCL; + } + return (CLIENT *)0; +} + +#if HAVE_IDENTD +/* use identd to verify a user at a host (ksb) + * we have a list of login@host:passwd:trust after the general host + * limits. We call identd/tap/auth to get info and compare + */ +IdentifyMe(pCL) +CLIENT *pCL; +{ + /* ZZZ */ + /* we would have to getsockname(fdClient) + * getpeername(fdClient) + * identd_client(addr, addr, acBuffer + * check for identifier in allowed list + * return the permision (modify in pCL) + */ +} +#endif + +/* show a character as a string so the user cannot mistake it for (ksb) + * another + * + * must pass us at least 16 characters to put fill with text + */ +char * +FmtCtl(ci, pcIn) +int ci; +char *pcIn; +{ + register char *pcOut = pcIn; + unsigned char c; + + c = ci & 0xff; + if (c > 127) { + c -= 128; + *pcOut++ = 'M'; + *pcOut++ = '-'; + } + + if (c < ' ' || c == '\177') { + *pcOut++ = '^'; + *pcOut++ = c ^ 0100; + *pcOut = '\000'; + } else if (c == ' ') { + (void)strcpy(pcOut, ""); + } else if (c == '^') { + (void)strcpy(pcOut, ""); + } else if (c == '\\') { + (void)strcpy(pcOut, ""); + } else { + *pcOut++ = c; + *pcOut = '\000'; + } + return pcIn; +} + +/* replay last iBack lines of the log file upon connect to console (ksb) + * + * NB: we know the console might be spewing when the replay happens, + * we want to just output what is in the log file and get out, + * so we don't drop chars... + */ +void +Replay(fdLog, fdOut, iBack) +int fdLog, fdOut, iBack; +{ + register int tot, nCr; + register char *pc; + register off_t where; + auto char bf[MAXREPLAY+2]; + auto struct stat stLog; + + if (-1 == fdLog) { + CSTROUT(fdOut, "[no log file on this console]\r\n"); + return; + } + + /* find the size of the file + */ + if (0 != fstat(fdLog, & stLog)) { + return; + } + + if (MAXREPLAY > stLog.st_size) { + where = 0L; + } else { + where = stLog.st_size - MAXREPLAY; + } + +#if defined(SEEK_SET) + /* PTX and maybe other Posix systems + */ + if (lseek(fdLog, where, SEEK_SET) < 0) { + return; + } +#else + if (lseek(fdLog, where, L_SET) < 0) { + return; + } +#endif + + if ((tot = read(fdLog, bf, MAXREPLAY)) <= 0) { + return; + } + bf[tot] = '@'; + + pc = & bf[tot]; + nCr = 0; + while (--pc != bf) { + if ('\n' == *pc && iBack == nCr++) { + ++pc; /* get rid of a blank line */ + break; + } + } + + (void)write(fdOut, pc, tot-(pc - bf)); +} + + +/* these bit tell us which parts of the Truth to tell the client (ksb) + */ +#define WHEN_SPY 0x01 +#define WHEN_ATTACH 0x02 +#define WHEN_VT100 0x04 +#define WHEN_EXPERT 0x08 /* ZZZ no way to set his yet */ +#define WHEN_ALWAYS 0x40 + +#define HALFLINE 40 +typedef struct HLnode { + int iwhen; + char actext[HALFLINE]; +} HELP; + +static HELP aHLTable[] = { + { WHEN_ALWAYS, ". disconnect"}, + { WHEN_ALWAYS, "a attach read/write"}, + { WHEN_ATTACH, "c toggle flow control"}, + { WHEN_ATTACH, "d down a console"}, + { WHEN_ALWAYS, "e change escape sequence"}, + { WHEN_ALWAYS, "f force attach read/write"}, + { WHEN_ALWAYS, "g group info"}, + { WHEN_ATTACH, "L toggle logging on/off"}, + { WHEN_ATTACH, "l1 send break (halt host!)"}, + { WHEN_ALWAYS, "o (re)open the tty and log file"}, + { WHEN_ALWAYS, "p replay the last 60 lines"}, + { WHEN_ALWAYS, "r replay the last 20 lines"}, + { WHEN_ATTACH, "s spy read only"}, + { WHEN_ALWAYS, "u show host status"}, + { WHEN_ALWAYS, "v show version info"}, + { WHEN_ALWAYS, "w who is on this console"}, + { WHEN_ALWAYS, "x show console baud info"}, + { WHEN_ALWAYS, "z suspend the connection"}, + { WHEN_ALWAYS, " ignore/abort command"}, + { WHEN_ALWAYS, "? print this message"}, + { WHEN_ALWAYS, "^R short replay"}, + { WHEN_ATTACH, "\\ooo send character by octal code"}, + { WHEN_EXPERT, "^I toggle tab expansion"}, + { WHEN_EXPERT, "; change to another console"}, + { WHEN_EXPERT, "+(-) do (not) drop line"}, + { WHEN_VT100, "PF1 print this message"}, + { WHEN_VT100, "PF2 disconnect"}, + { WHEN_VT100, "PF3 replay the last 20 lines"}, + { WHEN_VT100, "PF4 spy read only"} +}; + +/* list the commands we know for the user (ksb) + */ +void +HelpUser(pCL) +CLIENT *pCL; +{ + register int i, j, iCmp; + static char + acH1[] = "help]\r\n", + acH2[] = "help spy mode]\r\n", + acEoln[] = "\r\n"; + auto char acLine[HALFLINE*2+3]; + + iCmp = WHEN_ALWAYS|WHEN_SPY; + if (pCL->fwr) { + (void)write(pCL->fd, acH1, sizeof(acH1)-1); + iCmp |= WHEN_ATTACH; + } else { + (void)write(pCL->fd, acH2, sizeof(acH2)-1); + } + if ('\033' == pCL->ic[0] && 'O' == pCL->ic[1]) { + iCmp |= WHEN_VT100; + } + + acLine[0] = '\000'; + for (i = 0; i < sizeof(aHLTable)/sizeof(HELP); ++i) { + if (0 == (aHLTable[i].iwhen & iCmp)) { + continue; + } + if ('\000' == acLine[0]) { + acLine[0] = ' '; + (void)strcpy(acLine+1, aHLTable[i].actext); + continue; + } + for (j = strlen(acLine); j < HALFLINE+1; ++j) { + acLine[j] = ' '; + } + (void)strcpy(acLine+j, aHLTable[i].actext); + (void)strcat(acLine+j, acEoln); + (void)write(pCL->fd, acLine, strlen(acLine)); + acLine[0] = '\000'; + } + if ('\000' != acLine[0]) { + (void)strcat(acLine, acEoln); + (void)write(pCL->fd, acLine, strlen(acLine)); + } +} diff --git a/conserver/client.h b/conserver/client.h new file mode 100644 index 0000000..2908367 --- /dev/null +++ b/conserver/client.h @@ -0,0 +1,72 @@ +/* + * $Id: client.h,v 5.10 1998-11-18 00:17:12-08 bryan Exp $ + * + * 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. + */ +/* 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 */ + +typedef struct client { /* Connection Information: */ + int fd; /* file descriptor */ + short fcon; /* currently connect or not */ + short fwr; /* (client) write enable flag */ + short fwantwr; /* (client) wants to write */ + short fecho; /* echo commands (not set by machines) */ + char acid[128]; /* login and location of client */ + long tym; /* time of connect */ + long typetym; /* time of last keystroke */ + char actym[32]; /* pre-formatted time */ + struct consent + *pCEwant, /* what machine we would like to be on */ + *pCEto; /* host a client gets output from */ + struct client + **ppCLbscan, /* back link for scan ptr */ + *pCLscan, /* next client fd to scan after select */ + **ppCLbnext, /* back link for next ptr */ + *pCLnext; /* next person on this list */ + char ic[2]; /* two character escape sequence */ + char iState; /* state for fsm in server */ + char caccess; /* did we trust the remote machine */ + char accmd[MAXSERVLEN+1];/* the command the user issued */ + int icursor; /* the length of the command issused */ + struct sockaddr_in + cnct_port; /* where from */ +} CLIENT; + +extern char *FmtCtl(); +extern void Replay(); +extern void HelpUser(); +extern CLIENT *FindWrite(); diff --git a/conserver/cons-gnac.h b/conserver/cons-gnac.h new file mode 100644 index 0000000..2ae9e65 --- /dev/null +++ b/conserver/cons-gnac.h @@ -0,0 +1,350 @@ +/* + * $Id: cons-gnac.h,v 5.38 1998-11-17 18:43:39-08 bryan Exp $ + * + * 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. + */ + +/* + * this is the configuration file for the Ohio State/PUCC console + * server. Just define the macros below to somehting that looks good + * and give it a go. It'll complain (under conserver -V) if things + * look really bad. + * + * all PTX, PTX2, and PTX4 code added by gregf@sequent.com (gregf) + */ +/* #define IBMR2 1 /**/ +/* #define HPUX7 1 /**/ +/* #define SUN4 1 /**/ +/* #define SUN5 1 /**/ +/* #define PTX2 1 /* DYNIX/ptx v2.X */ +/* #define PTX4 1 /* DYNIX/ptx v4.0 */ + +#if (defined(PTX2) || defined(PTX4)) +#define PTX +#endif + +/* some machine specific details + */ +#if !defined(USE_OLDSEL) +#if defined(IBMR2) +#include +#endif +#endif +#if !defined(HAVE_UWAIT) +#define HAVE_UWAIT !(defined(IBMR2)||defined(SUN5)||defined(HPUX8)||defined(HPUX9)||defined(PTX)||defined(IRIX5)) +#endif + +#if !defined(HAVE_WAIT3) +#define HAVE_WAIT3 !(defined(SUN5)||defined(PTX)) +#endif + +/* This is the port number used in the connection. It can use either + * /etc/services or a hardcoded port (SERVICE name has precedence). + * (You can -D one in the Makefile to override these.) + */ +/* #define PORT 782 /* only if you cannot put in /etc/services */ +#if !defined(SERVICE) +#if !defined(PORT) +#define SERVICE "conserver" +#endif +#endif + +/* Wait for a part of a second before slapping console server. + * Good for CISCO terminal servers that get upset when you + * attack with intense socket connections + */ +#if !defined(USLEEP_FOR_SLOW_PORTS) +#define USLEEP_FOR_SLOW_PORTS 100000 +#endif + +/* The name of the host which will act as the console server + */ +#if !defined(HOST) +#define HOST "console" +#endif + +/* the default escape sequence used to give meta commands + */ +#define DEFATTN '\005' +#define DEFESC 'c' + +/* Location of the configuration file + */ +#if !defined(CONFIG) +#define CONFIG "/etc/conserver.cf" +#endif + +/* Location of ANL designed passwd file */ +#if !defined(PASSWD_FILE) +#define PASSWD_FILE "/etc/conserver.passwd" +#endif + +/* The maximum number of serial lines that can be handled by a child process + */ +#if !defined(MAXMEMB) +#define MAXMEMB 8 +#endif + + +/* The maximum number of child processes spawned. + */ +#if !defined(MAXGRP) +#define MAXGRP 32 +#endif + +/* the max number of characters conserver will replay for you (the r command) + */ +#if !defined(MAXREPLAY) +#define MAXREPLAY (80*25) +#endif + +/* if the encrypted passwd is in a shadow file, define HAVE_SHADOW (gregf) + */ +#if !defined(HAVE_SHADOW) +#define HAVE_SHADOW (defined(PTX)||defined(SUN5)) +#endif + +/* we'd like to line buffer our output, if we know how + */ +#if !defined(USE_SETLINEBUF) +#define USE_SETLINEBUF (!(defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(PTX))) +#endif + +/* we'd like to line buffer our output, if we know how; PTX uses setvbuf (gregf) + */ +#if !defined(USE_SETVBUF) +#define USE_SETVBUF (defined(PTX)) +#endif + +/* hpux doesn't have getdtablesize() and they don't provide a macro + * in non-KERNEL cpp mode + */ +#if defined(HPUX7)||defined(HPUX8)||defined(HPUX9) +#define getdtablesize() 64 +#endif + +/* the console server will provide a pseudo-device console which + * allows operators to run backups and such without a hard wired + * line (this is also good for testing the server to see if you + * might wanna use it). Turn this on only if you (might) need it. + */ +#if !defined(DO_VIRTUAL) +#define DO_VIRTUAL 1 +#endif + +#if DO_VIRTUAL +/* if the virtual console option is on we need a source to ptys, + * the PUCC ptyd daemon is the best source be know, else fall back + * on some emulation code?? (XXX) + */ +#if !defined(HAVE_PTYD) +#define HAVE_PTYD (defined(S81)||defined(VAX8800)) +#endif + +#if !defined(HAVE_GETPSEUDO) +#define HAVE_GETPSEUDO (defined(PTX2)) +#endif + +#if !defined(HAVE_PTSNAME) +#define HAVE_PTSNAME (defined(PTX4)) +#endif + +#if !defined(HAVE_LDTERM) +#define HAVE_LDTERM (defined(SUN5)) +#endif + +#if !defined(HAVE_STTY_LD) +#define HAVE_STTY_LD (defined(IRIX5)) +#endif + +#endif /* virtual (process on a pseudo-tty) console support */ + +#if !defined(HAVE_SETSID) +#define HAVE_SETSID (defined(IBMR2)||defined(SUN5)||defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(PTX)||defined(IRIX5)) +#endif + +/* should we use flock to keep multiple conservers from hurting each other? + * PTX has lockf... should probably port code to work with this (gregf) + */ +#if !defined(USE_FLOCK) +#define USE_FLOCK (!(defined(IBMR2)||defined(SUN5)||defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(PTX))) +#endif + +/* should we try to pop streams modules off? + */ +#if !defined(USE_STREAMS) +#define USE_STREAMS (defined(SUN4)||defined(SUN5)||defined(PTX)||defined(IRIX5)) +#endif + +/* if we do not have old style tty emulation use termios.h + */ +#if !defined(USE_TERMIO) +#define USE_TERMIO (defined(ETA10)||defined(V386)) +#endif +#if !defined(USE_TERMIOS) +#define USE_TERMIOS (defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(SUN5)||defined(PTX)||defined(IRIX5)) +#endif +#if !defined(USE_TCBREAK) +#define USE_TCBREAK (defined(SUN4)||defined(PTX)) +#endif + +/* if we have define this to 1, else define to 0 + */ +#if !defined(USE_STRINGS) +#define USE_STRINGS (defined(SUN4)||defined(DYNIX)||defined(EPIX)||defined(IRIX5)) +#endif + +#if !defined(NEED_UNISTD_H) +#define NEED_UNISTD_H (defined(SUN5)||defined(PTX)) +#endif + +#if !defined(USE_SYS_TIME_H) +#define USE_SYS_TIME_H (!defined(PTX)) +#endif + +#if USE_STRINGS +#define strchr index +#define strrchr rindex +#endif + +/* used to force the server process to clear parity, which is for farmers + */ +#define CPARITY 1 + + +/* if you do not have fd_set's here is a possible emulation + */ +#if USE_OLDSEL +typedef long fd_set; + +#define FD_ZERO(a) {*(a)=0;} +#define FD_SET(d,a) {*(a) |= (1 << (d));} +#define FD_CLR(d,a) {*(a) &= ~(1 << (d));} +#define FD_ISSET(d,a) (*(a) & (1 << (d))) +#endif + +#if USE_TERMIOS +#if defined(HPUX7)||defined(HPUX8)||defined(HPUX9) +#define TCGETS _IOR('T', 16, struct termios) +#define TCSETS _IOW('T', 17, struct termios) +#endif +#if defined(PTX2) +#define TCGETS TCGETP +#define TCSETS TCSETP +#endif +#endif + +/* which type does wait(2) take for status location + */ +#if HAVE_UWAIT +#define WAIT_T union wait +#if ! defined WEXITSTATUS +#define WEXITSTATUS(x) ((x).w_retcode) +#endif +#else +#define WAIT_T int +#endif + +/* which type signal handlers return on this machine + */ +#if defined(sun) || defined(NEXT2) || defined(SUN5) || defined(PTX) || defined(IRIX5) +#define SIGRETS void +#else +#define SIGRETS int +#endif + +/* do we have a (working) setsockopt call + */ +#if !defined(HAVE_SETSOCKOPT) +#define HAVE_SETSOCKOPT (defined(sun)||defined(PTX)) +#endif + +/* does this system have the ANSI strerror() function? + */ +#if !defined(HAVE_STRERROR) +#define HAVE_STRERROR (defined(IBMR2)||defined(ETA10)||defined(V386)||defined(SUN5)||defined(NEXT2)||defined(HPUX8)||defined(HPUX9)||defined(PTX)||defined(IRIX5)) +#endif +#if ! HAVE_STRERROR +extern int errno; +extern char *sys_errlist[]; +#define strerror(Me) (sys_errlist[Me]) +#endif + +#if !defined(HAVE_H_ERRLIST) +#define HAVE_H_ERRLIST (defined(SUN4)||defined(SUN3)||defined(FREEBSD)|defined(NETBSD)||defined(PTX)||defined(IRIX5)) +#endif +#if HAVE_H_ERRLIST +extern int h_errno; +extern char *h_errlist[]; +#define hstrerror(Me) (h_errlist[Me]) +#else +#define hstrerror(Me) "host lookup error" +#endif + +#if !defined(HAVE_RLIMIT) +#if (defined(SUN5)||defined(PTX4)) +#define HAVE_RLIMIT 1 +#else +#define HAVE_RLIMIT 0 +#endif +#endif + +/* that's all. just run + * make + * ./conserver -V + */ + +/* communication constants + */ +#define OB_SUSP 'Z' /* suspended by server */ +#define OB_DROP '.' /* dropped by server */ + +/* Due to C's poor man's macros the macro below would break if statements, + * What we want + * macro() { stuff } + * but the syntax gives us + * macro() { stuff }; + * + * the extra semicolon breaks if statements! + * Of course, the one we use makes lint scream: + * macro() do { stuff } while (0) + * + * which is a statement and makes if statements safe + */ +#if defined(lint) +extern int shut_up_lint; +#else +#define shut_up_lint 0 +#endif + +/* this macro efficently outputs a constant string to a fd + * of course it doesn't check the write :-( + */ +#define CSTROUT(Mfd, Mstr) do { \ + static char _ac[] = Mstr; \ + write(Mfd, _ac, sizeof(_ac)-1); \ + } while (shut_up_lint) + +extern char *calloc(), *malloc(), *realloc(); diff --git a/conserver/cons-test.h b/conserver/cons-test.h new file mode 100644 index 0000000..2d9d893 --- /dev/null +++ b/conserver/cons-test.h @@ -0,0 +1,351 @@ +/* + * $Id: cons-gnac.h,v 5.35 1997-02-23 18:32:38-08 bryan Exp $ + * + * 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. + */ + +/* + * this is the configuration file for the Ohio State/PUCC console + * server. Just define the macros below to somehting that looks good + * and give it a go. It'll complain (under conserver -V) if things + * look really bad. + * + * all PTX, PTX2, and PTX4 code added by gregf@sequent.com (gregf) + */ +/* #define IBMR2 1 /**/ +/* #define HPUX7 1 /**/ +/* #define SUN4 1 /**/ +/* #define SUN5 1 /**/ +/* #define PTX2 1 /* DYNIX/ptx v2.X */ +/* #define PTX4 1 /* DYNIX/ptx v4.0 */ + +#if (defined(PTX2) || defined(PTX4)) +#define PTX +#endif + +/* some machine specific details + */ +#if !defined(USE_OLDSEL) +#if defined(IBMR2) +#include +#endif +#endif +#if !defined(HAVE_UWAIT) +#define HAVE_UWAIT !(defined(IBMR2)||defined(SUN5)||defined(HPUX8)||defined(HPUX9)||defined(PTX)||defined(IRIX5)) +#endif + +#if !defined(HAVE_WAIT3) +#define HAVE_WAIT3 !(defined(SUN5)||defined(PTX)) +#endif + +/* This is the port number used in the connection. It can use either + * /etc/services or a hardcoded port (SERVICE name has precedence). + * (You can -D one in the Makefile to override these.) + */ +/* #define PORT 782 /* only if you cannot put in /etc/services */ +#define PORT 7777 +#if !defined(SERVICE) +#if !defined(PORT) +#define SERVICE "conserver" +#endif +#endif + +/* Wait for a part of a second before slapping console server. + * Good for CISCO terminal servers that get upset when you + * attack with intense socket connections + */ +#if !defined(USLEEP_FOR_SLOW_PORTS) +#define USLEEP_FOR_SLOW_PORTS 100000 +#endif + +/* The name of the host which will act as the console server + */ +#if !defined(HOST) +#define HOST "localhost" +#endif + +/* the default escape sequence used to give meta commands + */ +#define DEFATTN '\005' +#define DEFESC 'c' + +/* Location of the configuration file + */ +#if !defined(CONFIG) +#define CONFIG "../conserver.cf/test.cf" +#endif + +/* Location of ANL designed passwd file */ +#if !defined(PASSWD_FILE) +#define PASSWD_FILE "./conserver.passwd" +#endif + +/* The maximum number of serial lines that can be handled by a child process + */ +#if !defined(MAXMEMB) +#define MAXMEMB 8 +#endif + + +/* The maximum number of child processes spawned. + */ +#if !defined(MAXGRP) +#define MAXGRP 32 +#endif + +/* the max number of characters conserver will replay for you (the r command) + */ +#if !defined(MAXREPLAY) +#define MAXREPLAY (80*25) +#endif + +/* if the encrypted passwd is in a shadow file, define HAVE_SHADOW (gregf) + */ +#if !defined(HAVE_SHADOW) +#define HAVE_SHADOW (defined(PTX)||defined(SUN5)) +#endif + +/* we'd like to line buffer our output, if we know how + */ +#if !defined(USE_SETLINEBUF) +#define USE_SETLINEBUF (!(defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(PTX))) +#endif + +/* we'd like to line buffer our output, if we know how; PTX uses setvbuf (gregf) + */ +#if !defined(USE_SETVBUF) +#define USE_SETVBUF (defined(PTX)) +#endif + +/* hpux doesn't have getdtablesize() and they don't provide a macro + * in non-KERNEL cpp mode + */ +#if defined(HPUX7)||defined(HPUX8)||defined(HPUX9) +#define getdtablesize() 64 +#endif + +/* the console server will provide a pseudo-device console which + * allows operators to run backups and such without a hard wired + * line (this is also good for testing the server to see if you + * might wanna use it). Turn this on only if you (might) need it. + */ +#if !defined(DO_VIRTUAL) +#define DO_VIRTUAL 1 +#endif + +#if DO_VIRTUAL +/* if the virtual console option is on we need a source to ptys, + * the PUCC ptyd daemon is the best source be know, else fall back + * on some emulation code?? (XXX) + */ +#if !defined(HAVE_PTYD) +#define HAVE_PTYD (defined(S81)||defined(VAX8800)) +#endif + +#if !defined(HAVE_GETPSEUDO) +#define HAVE_GETPSEUDO (defined(PTX2)) +#endif + +#if !defined(HAVE_PTSNAME) +#define HAVE_PTSNAME (defined(PTX4)) +#endif + +#if !defined(HAVE_LDTERM) +#define HAVE_LDTERM (defined(SUN5)) +#endif + +#if !defined(HAVE_STTY_LD) +#define HAVE_STTY_LD (defined(IRIX5)) +#endif + +#endif /* virtual (process on a pseudo-tty) console support */ + +#if !defined(HAVE_SETSID) +#define HAVE_SETSID (defined(IBMR2)||defined(SUN5)||defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(PTX)||defined(IRIX5)) +#endif + +/* should we use flock to keep multiple conservers from hurting each other? + * PTX has lockf... should probably port code to work with this (gregf) + */ +#if !defined(USE_FLOCK) +#define USE_FLOCK (!(defined(IBMR2)||defined(SUN5)||defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(PTX))) +#endif + +/* should we try to pop streams modules off? + */ +#if !defined(USE_STREAMS) +#define USE_STREAMS (defined(SUN4)||defined(SUN5)||defined(PTX)||defined(IRIX5)) +#endif + +/* if we do not have old style tty emulation use termios.h + */ +#if !defined(USE_TERMIO) +#define USE_TERMIO (defined(ETA10)||defined(V386)) +#endif +#if !defined(USE_TERMIOS) +#define USE_TERMIOS (defined(HPUX7)||defined(HPUX8)||defined(HPUX9)||defined(SUN5)||defined(PTX)||defined(IRIX5)) +#endif +#if !defined(USE_TCBREAK) +#define USE_TCBREAK (defined(SUN4)||defined(PTX)) +#endif + +/* if we have define this to 1, else define to 0 + */ +#if !defined(USE_STRINGS) +#define USE_STRINGS (defined(SUN4)||defined(DYNIX)||defined(EPIX)||defined(IRIX5)) +#endif + +#if !defined(NEED_UNISTD_H) +#define NEED_UNISTD_H (defined(SUN5)||defined(PTX)) +#endif + +#if !defined(USE_SYS_TIME_H) +#define USE_SYS_TIME_H (!defined(PTX)) +#endif + +#if USE_STRINGS +#define strchr index +#define strrchr rindex +#endif + +/* used to force the server process to clear parity, which is for farmers + */ +#define CPARITY 1 + + +/* if you do not have fd_set's here is a possible emulation + */ +#if USE_OLDSEL +typedef long fd_set; + +#define FD_ZERO(a) {*(a)=0;} +#define FD_SET(d,a) {*(a) |= (1 << (d));} +#define FD_CLR(d,a) {*(a) &= ~(1 << (d));} +#define FD_ISSET(d,a) (*(a) & (1 << (d))) +#endif + +#if USE_TERMIOS +#if defined(HPUX7)||defined(HPUX8)||defined(HPUX9) +#define TCGETS _IOR('T', 16, struct termios) +#define TCSETS _IOW('T', 17, struct termios) +#endif +#if defined(PTX2) +#define TCGETS TCGETP +#define TCSETS TCSETP +#endif +#endif + +/* which type does wait(2) take for status location + */ +#if HAVE_UWAIT +#define WAIT_T union wait +#if ! defined WEXITSTATUS +#define WEXITSTATUS(x) ((x).w_retcode) +#endif +#else +#define WAIT_T int +#endif + +/* which type signal handlers return on this machine + */ +#if defined(sun) || defined(NEXT2) || defined(SUN5) || defined(PTX) || defined(IRIX5) +#define SIGRETS void +#else +#define SIGRETS int +#endif + +/* do we have a (working) setsockopt call + */ +#if !defined(HAVE_SETSOCKOPT) +#define HAVE_SETSOCKOPT (defined(sun)||defined(PTX)) +#endif + +/* does this system have the ANSI strerror() function? + */ +#if !defined(HAVE_STRERROR) +#define HAVE_STRERROR (defined(IBMR2)||defined(ETA10)||defined(V386)||defined(SUN5)||defined(NEXT2)||defined(HPUX8)||defined(HPUX9)||defined(PTX)||defined(IRIX5)) +#endif +#if ! HAVE_STRERROR +extern int errno; +extern char *sys_errlist[]; +#define strerror(Me) (sys_errlist[Me]) +#endif + +#if !defined(HAVE_H_ERRLIST) +#define HAVE_H_ERRLIST (defined(SUN4)||defined(SUN3)||defined(FREEBSD)|defined(NETBSD)||defined(PTX)||defined(IRIX5)) +#endif +#if HAVE_H_ERRLIST +extern int h_errno; +extern char *h_errlist[]; +#define hstrerror(Me) (h_errlist[Me]) +#else +#define hstrerror(Me) "host lookup error" +#endif + +#if !defined(HAVE_RLIMIT) +#if (defined(SUN5)||defined(PTX4)) +#define HAVE_RLIMIT 1 +#else +#define HAVE_RLIMIT 0 +#endif +#endif + +/* that's all. just run + * make + * ./conserver -V + */ + +/* communication constants + */ +#define OB_SUSP 'Z' /* suspended by server */ +#define OB_DROP '.' /* dropped by server */ + +/* Due to C's poor man's macros the macro below would break if statements, + * What we want + * macro() { stuff } + * but the syntax gives us + * macro() { stuff }; + * + * the extra semicolon breaks if statements! + * Of course, the one we use makes lint scream: + * macro() do { stuff } while (0) + * + * which is a statement and makes if statements safe + */ +#if defined(lint) +extern int shut_up_lint; +#else +#define shut_up_lint 0 +#endif + +/* this macro efficently outputs a constant string to a fd + * of course it doesn't check the write :-( + */ +#define CSTROUT(Mfd, Mstr) do { \ + static char _ac[] = Mstr; \ + write(Mfd, _ac, sizeof(_ac)-1); \ + } while (shut_up_lint) + +extern char *calloc(), *malloc(), *realloc(); diff --git a/conserver/cons.h b/conserver/cons.h new file mode 120000 index 0000000..a914e64 --- /dev/null +++ b/conserver/cons.h @@ -0,0 +1 @@ +cons-test.h \ No newline at end of file diff --git a/conserver/consent.c b/conserver/consent.c new file mode 100644 index 0000000..2b0d4ac --- /dev/null +++ b/conserver/consent.c @@ -0,0 +1,710 @@ +/* + * $Id: consent.c,v 5.30 1998-11-20 17:30:45-08 bryan Exp $ + * + * 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. + */ + +/* + * Network console modifications by Robert Olson, olson@mcs.anl.gov. + */ +#ifndef lint +static char copyright[] = +"@(#) Copyright 1992 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "consent.h" +#include "client.h" +#include "main.h" + +#if USE_TERMIO +#include + +#else +#if USE_TERMIOS +#include +#include + +#else /* use ioctl stuff */ +#include +#include +#endif +#endif + +#if USE_STREAMS +#include +#endif + +#if USE_STRINGS +#include +#else +#include +#endif + + +BAUD baud [] = { + { "Netwk", 0 }, +#if defined(B38400) + { "38400", B38400 }, +#endif +#if defined(B19200) + { "19200", B19200 }, +#endif + { "9600", B9600 }, + { "4800", B4800 }, + { "2400", B2400 }, +#if defined(B1800) + { "1800", B1800 }, +#endif + { "1200", B1200 }, +#if defined(B600) + { "600", B600 }, +#endif +}; + + +/* find a baud rate for the string "9600x" -> B9600 (ksb) + */ +BAUD * +FindBaud(pcMode) +char *pcMode; +{ + register 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; + } + return baud; +} + + +PARITY parity[] = { +#if USE_TERMIOS +#if !defined(PAREXT) +#define PAREXT 0 +#endif + {' ', 0, 0}, /* Blank for network */ + {'e', PARENB|CS7, 0}, /* even */ + {'m', PARENB|CS7|PARODD|PAREXT, 0}, /* mark */ + {'o', PARENB|CS7|PARODD, 0}, /* odd */ + {'p', CS8, 0}, /* pass 8 bits, no parity */ + {'s', PARENB|CS7|PAREXT, 0}, /* space */ +#else + {' ', 0, 0}, /* Blank for network */ + {'e', EVENP, ODDP}, /* even */ + {'m', EVENP|ODDP, 0}, /* mark */ + {'o', ODDP, EVENP}, /* odd */ +#if defined(PASS8) + {'p', PASS8,EVENP|ODDP},/* pass 8 bits, no parity */ +#endif + {'s', 0, EVENP|ODDP} /* space */ +#endif +}; + +/* find a parity on the end of a baud "9600even" -> EVEN (ksb) + */ +PARITY * +FindParity(pcMode) +char *pcMode; +{ + register int i; + auto char acFirst; + + while (isdigit(*pcMode)) { + ++pcMode; + } + acFirst = *pcMode; + if (isupper(acFirst)) + acFirst = tolower(acFirst); + for (i = 0; i < sizeof(parity)/sizeof(struct parity); ++i) { + if (acFirst != parity[i].ckey) + continue; + return parity+i; + } + return parity; +} + + +#if USE_TERMIOS +/* setup a tty device (ksb) + */ +static int +TtyDev(pCE) +CONSENT *pCE; +{ + struct termios termp; + auto struct stat stPerm; + + /* here we should fstat for `read-only' checks + */ + if (-1 == fstat(pCE->fdtty, & stPerm)) { + fprintf(stderr, "%s: fstat: %s: %s\n", progname, pCE->dfile, strerror(errno)); + } else if (0 == (stPerm.st_mode & 0222)) { + /* any device that is read-only we won't write to + */ + pCE->fronly = 1; + } + + /* + * Get terminal attributes + */ + if (-1 == tcgetattr(pCE->fdtty, &termp)) { + fprintf(stderr, "%s: tcgetattr: %s(%d): %s\n", progname, pCE->dfile, pCE->fdtty, strerror(errno)); + return -1; + } + + /* + * Turn off: echo + * icrnl + * opost No post processing + * icanon No line editing + * isig No signal generation + * Turn on: ixoff + */ + termp.c_iflag = IXON|IXOFF|BRKINT; + termp.c_oflag = 0; + termp.c_cflag = CREAD; + termp.c_cflag |= pCE->pparity->iset; + termp.c_lflag = 0; + /* + * Set the VMIN == 128 + * Set the VTIME == 1 (0.1 sec) + * Don't bother with the control characters as they are not used + */ + termp.c_cc[VMIN] = 128; + termp.c_cc[VTIME] = 1; + + if (-1 == cfsetospeed(&termp,pCE->pbaud->irate)) { + fprintf(stderr, "%s: cfsetospeed: %s(%d): %s\n", progname, pCE->dfile, pCE->fdtty, strerror(errno)); + return -1; + } + if (-1 == cfsetispeed(&termp,pCE->pbaud->irate)) { + fprintf(stderr, "%s: cfsetispeed: %s(%d): %s\n", progname, pCE->dfile, pCE->fdtty, strerror(errno)); + return -1; + } + + /* + * Set terminal attributes + */ + if (-1 == tcsetattr(pCE->fdtty, TCSADRAIN, &termp)) { + fprintf(stderr, "%s: tcsetattr: %s(%d): %s\n", progname, pCE->dfile, pCE->fdtty, strerror(errno)); + return -1; + } + +#if USE_STREAMS + /* + * eat all the streams modules upto and including ttcompat + */ + while (ioctl(pCE->fdtty, I_FIND, "ttcompat") == 0) { + (void)ioctl(pCE->fdtty, I_POP, 0); + } +#endif + pCE->fup = 1; + return 0; +} +#else + +/* setup a tty device (ksb) + */ +static int +TtyDev(pCE) +CONSENT *pCE; +{ + struct sgttyb sty; + struct tchars m_tchars; + struct ltchars m_ltchars; + auto struct stat stPerm; + + /* here we should fstat for `read-only' checks + */ + if (-1 == fstat(pCE->fdtty, & stPerm)) { + fprintf(stderr, "%s: fstat: %s: %s\n", progname, pCE->dfile, strerror(errno)); + } else if (0 == (stPerm.st_mode & 0222)) { + /* any device that is read-only we won't write to + */ + pCE->fronly = 1; + } + +#if USE_SOFTCAR +#if defined(TIOCSSOFTCAR) + if (-1 == ioctl(pCE->fdtty, TIOCSSOFTCAR, &fSoftcar)) { + fprintf(stderr, "%s: softcar: %d: %s\n", progname, pCE->fdtty, strerror(errno)); + return -1; + } +#endif +#endif + + /* stty 9600 raw cs7 + */ + if (-1 == ioctl(pCE->fdtty, TIOCGETP, (char *)&sty)) { + fprintf(stderr, "%s: ioctl1: %s(%d): %s\n", progname, pCE->dfile, pCE->fdtty, strerror(errno)); + 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)) { + fprintf(stderr, "%s: ioctl2: %d: %s\n", progname, pCE->fdtty, strerror(errno)); + 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)) { + fprintf(stderr, "%s: ioctl3: %d: %s\n", progname, pCE->fdtty, strerror(errno)); + 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)) { + fprintf(stderr, "%s: ioctl4: %d: %s\n", progname, pCE->fdtty, strerror(errno)); + return -1; + } + if (-1 == ioctl(pCE->fdtty, TIOCGLTC, (char *)&m_ltchars)) { + fprintf(stderr, "%s: ioctl5: %d: %s\n", progname, pCE->fdtty, strerror(errno)); + 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)) { + fprintf(stderr, "%s: ioctl6: %d: %s\n", progname, pCE->fdtty, strerror(errno)); + return -1; + } +#if USE_STREAMS + /* 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 + +#if DO_VIRTUAL +/* setup a virtual device (ksb) + */ +static int +VirtDev(pCE) +CONSENT *pCE; +{ +#if USE_TERMIOS + static struct termios n_tio; +#else + auto struct sgttyb sty; + auto struct tchars m_tchars; + auto struct ltchars m_ltchars; +#endif +#if HAVE_RLIMIT + auto struct rlimit rl; +#endif + auto int i, iNewGrp; + auto int fd; + extern char **environ; + register char *pcShell, **ppcArgv; + + (void)fflush(stdout); + + switch (pCE->ipid = fork()) { + case -1: + return -1; + case 0: + break; + default: + fprintf(stderr, "%s: %d is the pid on %s\n", progname, pCE->ipid, pCE->acslave); + (void)fflush(stderr); + pCE->fup = 1; + sleep(2); /* chance to open line */ + return 0; + } + + /* put the signals back that we trap + */ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + + /* setup new process with clean filew descriptors + */ +#if HAVE_RLIMIT + getrlimit(RLIMIT_NOFILE, &rl); + i = rl.rlim_cur; +#else + i = getdtablesize(); +#endif + for (/* i above */; i-- > 2; ) { + close(i); + } + /* leave 2 until we *have to close it* + */ + close(1); + close(0); +#if defined(TIOCNOTTY) + if (-1 != (i = open("/dev/tty", 2, 0))) { + ioctl(i, TIOCNOTTY, (char *)0); + close(i); + } +#endif + +#if HAVE_SETSID + iNewGrp = setsid(); + if (-1 == iNewGrp) { + fprintf(stderr, "%s: %s: setsid: %s\n", progname, pCE->server, strerror(errno)); + iNewGrp = getpid(); + } +#else + iNewGrp = getpid(); +#endif + + if (0 != open(pCE->acslave, 2, 0) || 1 != dup(0)) { + fprintf(stderr, "%s: %s: fd sync error\n", progname, pCE->server); + exit(1); + } +#if HAVE_PTSNAME + /* SYSVr4 semantics for opening stream ptys (gregf) + * under PTX (others?) we have to push the compatibility + * streams modules `ptem' and `ld' + */ + (void)ioctl(0, I_PUSH, "ptem"); + (void)ioctl(0, I_PUSH, "ld"); +#endif +#if HAVE_LDTERM + (void)ioctl(0, I_PUSH, "ptem"); + (void)ioctl(0, I_PUSH, "ldterm"); +#endif +#if HAVE_STTY_LD + (void)ioctl(0, I_PUSH, "stty_ld"); +#endif + +#if USE_TERMIOS + if (0 != ioctl(0, TCGETS, & n_tio)) { + fprintf(stderr, "%s: iotcl: getsw: %s\n", progname, strerror(errno)); + exit(1); + } + n_tio.c_iflag &= ~(IGNCR|IUCLC); + n_tio.c_iflag |= ICRNL|IXON|IXANY; + n_tio.c_oflag &= ~(OLCUC|ONOCR|ONLRET|OFILL|NLDLY|CRDLY|TABDLY|BSDLY); + n_tio.c_oflag |= OPOST|ONLCR; + n_tio.c_lflag &= ~(XCASE|NOFLSH|ECHOK|ECHONL); + n_tio.c_lflag |= ISIG|ICANON|ECHO; + n_tio.c_cc[VEOF] = '\004'; + n_tio.c_cc[VEOL] = '\000'; + n_tio.c_cc[VERASE] = '\010'; + n_tio.c_cc[VINTR] = '\003'; + n_tio.c_cc[VKILL] = '@'; + /* MIN */ + n_tio.c_cc[VQUIT] = '\034'; + n_tio.c_cc[VSTART] = '\021'; + n_tio.c_cc[VSTOP] = '\023'; + n_tio.c_cc[VSUSP] = '\032'; + if (0 != ioctl(0, TCSETS, & n_tio)) { + fprintf(stderr, "%s: getarrt: %s\n", progname, strerror(errno)); + exit(1); + } + + tcsetpgrp(0, iNewGrp); +#else + /* stty 9600 raw cs7 + */ + if (-1 == ioctl(0, TIOCGETP, (char *)&sty)) { + fprintf(stderr, "%s: ioctl1: %s: %s\n", progname, pCE->fdtty, strerror(errno)); + exit(1); + } + 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)) { + fprintf(stderr, "%s: ioctl2: %s\n", progname, strerror(errno)); + exit(1); + } + + /* 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)) { + fprintf(stderr, "%s: ioctl3: %s\n", progname, strerror(errno)); + exit(1); + } + 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)) { + fprintf(stderr, "%s: ioctl4: %s\n", progname, strerror(errno)); + exit(1); + } + if (-1 == ioctl(0, TIOCGLTC, (char *)&m_ltchars)) { + fprintf(stderr, "%s: ioctl5: %s\n", progname, strerror(errno)); + exit(1); + } + 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)) { + fprintf(stderr, "%s: ioctl6: %s\n", progname, strerror(errno)); + exit(1); + } + + /* give us a process group to work in + */ + ioctl(0, TIOCGPGRP, (char *)&i); + setpgrp(0, i); + ioctl(0, TIOCSPGRP, (char *)&iNewGrp); + setpgrp(0, iNewGrp); +#endif + + close(2); + (void)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 ('\000' == pCE->pccmd[0]) { + static char *apcArgv[] = { + "-shell", "-i", (char *)0 + }; + register struct passwd *pwd; + + if ((struct passwd *)0 != (pwd = getpwuid(0)) && '\000' != pwd->pw_shell[0]) { + pcShell = pwd->pw_shell; + } + ppcArgv = apcArgv; + } else { + static char *apcArgv[] = { + "/bin/sh", "-ce", (char *)0, (char *)0 + }; + + apcArgv[2] = pCE->pccmd; + ppcArgv = apcArgv; + } + execve(pcShell, ppcArgv, environ); + fprintf(stderr, "execve: %s\n", strerror(errno)); + exit(1); + /*NOTREACHED*/ +} +#endif + +/* down a console, virtual or real (ksb) + */ +void +ConsDown(pCE, pfdSet) +CONSENT *pCE; +fd_set *pfdSet; +{ +#if DO_VIRTUAL + if (-1 != pCE->ipid) { + if (-1 != kill(pCE->ipid, SIGHUP)) + sleep(1); + pCE->ipid = -1; + } +#endif + if (-1 != pCE->fdtty) { + FD_CLR(pCE->fdtty, pfdSet); +#if DO_VIRTUAL + if (0 == pCE->fvirtual) { + (void)close(pCE->fdtty); + pCE->fdtty = -1; + } +#else + (void)close(pCE->fdtty); + pCE->fdtty = -1; +#endif + } + if (-1 != pCE->fdlog) { + if (pCE->nolog) { + CSTROUT(pCE->fdlog, "[Console logging restored]\r\n"); + } + (void)close(pCE->fdlog); + pCE->fdlog = -1; + } + pCE->fup = 0; + pCE->nolog = 0; +} + +/* set up a console the way it should be for use to work with it (ksb) + * also, recover from silo over runs by dropping the line and re-opening + * We also maintian the select set for the caller. + */ +void +ConsInit(pCE, pfdSet) +CONSENT *pCE; +fd_set *pfdSet; +{ + /* clean up old stuff + */ + ConsDown(pCE, pfdSet); + + pCE->fronly = 0; + pCE->nolog = 0; + (void)strcpy(pCE->acline, pCE->server); + pCE->inamelen = strlen(pCE->server); + pCE->acline[pCE->inamelen++] = ':'; + pCE->acline[pCE->inamelen++] = ' '; + pCE->iend = pCE->inamelen; + + + /* try to open them again + */ + if (-1 == + (pCE->fdlog = open(pCE->lfile, O_RDWR|O_CREAT|O_APPEND, 0644))) + { + fprintf(stderr, + "%s: open: %s: %s\n", + progname, pCE->lfile, strerror(errno)); + return; + } + +#if DO_VIRTUAL + if (0 != pCE->fvirtual) + { + /* still open, never ever close it, but set the bit */ + FD_SET(pCE->fdtty, pfdSet); + } + else if (pCE->isNetworkConsole) + { + struct sockaddr_in port; + struct hostent *hp; + int one = 1; + +#ifdef USLEEP_FOR_SLOW_PORTS + usleep( USLEEP_FOR_SLOW_PORTS ); /* Sleep for slow network ports */ +#endif + + bzero(&port, sizeof(port)); + + if ((hp = gethostbyname(pCE->networkConsoleHost)) == NULL) + { + fprintf(stderr, "%s: gethostbyname %s failed\n", + progname, pCE->networkConsoleHost); + exit(1); + } + + bcopy(hp->h_addr, &port.sin_addr, hp->h_length); + port.sin_family = hp->h_addrtype; + port.sin_port = htons(pCE->networkConsolePort); + + if ((pCE->fdtty = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + fprintf(stderr, "%s: socket: %s\n", progname, strerror(errno)); + exit(1); + } + if (setsockopt(pCE->fdtty, SOL_SOCKET, SO_KEEPALIVE, + (char *) &one, sizeof(one)) < 0) + { + fprintf(stderr, "%s: setsockopt SO_KEEPALIVE: %s\n", + progname, strerror(errno)); + } + if (connect(pCE->fdtty, + (struct sockaddr *)&port, sizeof(port)) < 0) + { + fprintf(stderr, "%s: connect: %s (%d@%s): %s: forcing down\n", + progname, pCE->server, ntohs(port.sin_port), + pCE->networkConsoleHost, strerror(errno)); + ConsDown(pCE, pfdSet); + return; + } + + /* + * Poke the connection to get the annex to wake up and + * register this connection. + */ +#ifdef POKE_ANNEX + write(pCE->fdtty, "\r\n", 2); +#endif + } else if (-1 == (pCE->fdtty = open(pCE->dfile, O_RDWR|O_NDELAY, 0600))) { + fprintf(stderr, "%s: open: %s: %s\n", progname, pCE->dfile, strerror(errno)); + (void)close(pCE->fdlog); + pCE->fdlog = -1; + 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); + } +#else + if (-1 == (pCE->fdtty = open(pCE->dfile, O_RDWR|O_NDELAY, 0600))) { + fprintf(stderr, "%s: open: %s: %s\n", progname, pCE->dfile, strerror(errno)); + (void)close(pCE->fdlog); + pCE->fdlog = -1; + return; + } + FD_SET(pCE->fdtty, pfdSet); + + /* ok, now setup the device + */ + TtyDev(pCE); +#endif +} diff --git a/conserver/consent.h b/conserver/consent.h new file mode 100644 index 0000000..61e4003 --- /dev/null +++ b/conserver/consent.h @@ -0,0 +1,89 @@ +/* + * $Id: consent.h,v 5.11 1998-12-14 11:20:15-08 bryan Exp $ + * + * 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. + */ +/* + * Network console modifications by Robert Olson, olson@mcs.anl.gov. + */ + + +/* stuff to keep track of a console entry + */ +typedef struct baud { /* a baud rate table */ + char acrate[8]; + int irate; +} BAUD; + +typedef struct parity { /* a parity bits table */ + char ckey; + int iset; + int iclr; +} PARITY; + +#define MAXSERVLEN 32 /* max length of server name */ +#define MAXDEVLEN 512 /* max length of /dev/ttyax */ +#define MAXLOGLEN 1024 /* max length of /usr/adm/consoles/foo */ +#define MAXTTYLINE (133*2) /* max length of a single buf'd line */ +#define ALARMTIME 60 /* time between chimes */ + +typedef struct consent { /* console information */ + char server[MAXSERVLEN];/* server name */ + char dfile[MAXDEVLEN]; /* device file */ + char lfile[MAXLOGLEN]; /* log file */ + BAUD *pbaud; /* the baud on this console port */ + PARITY *pparity; /* the parity on this line */ + int mark; /* Mark (chime) interval */ + long nextMark; /* Next mark (chime) time */ + + /* Used if network console */ + int isNetworkConsole; + char networkConsoleHost[MAXSERVLEN]; + int networkConsolePort; + +#if DO_VIRTUAL + /* used if virtual console */ + char acslave[MAXDEVLEN];/* pseudo-device slave side */ + int fvirtual; /* is a pty device we use as a console */ + char *pccmd; /* virtual console command */ + int ipid; /* pid of virtual command */ +#endif + /* only used in child */ + int nolog; /* don't log output */ + int fdlog; /* the local log file */ + int fdtty; /* the port to talk to machine on */ + short int fup; /* we setup this line? */ + short int fronly; /* we can only read this console */ + short int iend; /* like icursor in CLIENT */ + short int inamelen; /* strlen(server) */ + struct client *pCLon; /* clients on this console */ + struct client *pCLwr; /* client that is writting on console */ + char acline[132*2+2]; /* max chars we will call a line */ +} CONSENT; + +extern PARITY *FindParity(); +extern BAUD *FindBaud(); +extern void ConsInit(); +extern void ConsDown(); diff --git a/conserver/conserver.8l b/conserver/conserver.8l new file mode 100644 index 0000000..47b735e --- /dev/null +++ b/conserver/conserver.8l @@ -0,0 +1,78 @@ +.\" @(#)conserver.8 01/06/91 OSU CIS; Thomas A. Fine +.\" $Id: conserver.8l,v 2.3 93/02/09 11:51:56 ldv Exp $ +.TH CONSERVER 8L "LOCAL" +.SH NAME +conserver \- console server daemon +.SH SYNOPSIS +.B conserver [\-\fBnv\fP] [\-\fBC\fP \fIconfig\fP] +.br +.B conserver [\-\fBhV\fP] +.SH DESCRIPTION +.B Conserver +is the daemon for the +.IR console (1L) +program. +It provides remote access to the server consoles, +and logs all console data. +Slave hosts which have no current connection might produce important +error messages, these unloved errors are labeled with a machine name +and output on stdout. +.PP +When started, it forks a child for each group in /usr/local/etc/conserver.cf, +and assigns each process a port number to listen on. +The \fIconsole\fP client program knows how to request port numbers and +forwards to find the various slave hosts. +.PP +.B Conserver +completely controls any connection to a controlled host. +All handling of escape sequenes is done by the server, +except the suspend sequence which is +sent as an out-of-band command to the client. +.PP +The +.B conserver +parent process will automatically respawn any child process that dies. +If the parent process receives a SIGTERM, it will propogate the signal +to its children. +.SH OPTIONS +.TP +.BI \-C config +With this option the invoker may specify an alternate confguration. +The default \fIconfig\fP is /usr/local/lib/conserver.cf. +.TP +.B \-h +Output a brief help message. +.TP +.B \-n +The \fIconserver\fP will \fBnot\fP output unloved console output to +stdout. +.TP +.B \-v +Echo the configuration as it is being read (be verbose). +.TP +.B \-V +Output the version of the console server (only) and exit. +.SH EXAMPLES +conserver: expert: login ksb +.br +tyro: panic: my brain hurts +.br +conserver: ksb shifts from expert to tyro +.br +conserver: tyro: logout ksb +.br +\... +.SH FILES +.TS +l l. +/usr/local/lib/conserver.cf description of console terminal lines +/usr/adm/\fIhost\fP.console log files for \fIhost\fP's console +/dev/tty?? terminal line device files +\fIstdout\fP summary of unloved console errors +.TE +.SH AUTHORS +Thomas A. Fine, Ohio State Computer Science +.br +Kevin S Braunsdorf, Purdue University Computing Center +.SH "SEE ALSO" +console(1L), conserver.cf(5L) diff --git a/conserver/conserver.man b/conserver/conserver.man new file mode 100644 index 0000000..524469a --- /dev/null +++ b/conserver/conserver.man @@ -0,0 +1,78 @@ +.\" @(#)conserver.8 01/06/91 OSU CIS; Thomas A. Fine +.\" $Id: conserver.man,v 2.3 93/02/09 11:51:56 ldv Exp $ +.TH CONSERVER 8L "LOCAL" +.SH NAME +conserver \- console server daemon +.SH SYNOPSIS +.B conserver [\-\fBnv\fP] [\-\fBC\fP \fIconfig\fP] +.br +.B conserver [\-\fBhV\fP] +.SH DESCRIPTION +.B Conserver +is the daemon for the +.IR console (1L) +program. +It provides remote access to the server consoles, +and logs all console data. +Slave hosts which have no current connection might produce important +error messages, these unloved errors are labeled with a machine name +and output on stdout. +.PP +When started, it forks a child for each group in /usr/local/etc/conserver.cf, +and assigns each process a port number to listen on. +The \fIconsole\fP client program knows how to request port numbers and +forwards to find the various slave hosts. +.PP +.B Conserver +completely controls any connection to a controlled host. +All handling of escape sequenes is done by the server, +except the suspend sequence which is +sent as an out-of-band command to the client. +.PP +The +.B conserver +parent process will automatically respawn any child process that dies. +If the parent process receives a SIGTERM, it will propogate the signal +to its children. +.SH OPTIONS +.TP +.BI \-C config +With this option the invoker may specify an alternate confguration. +The default \fIconfig\fP is /usr/local/lib/conserver.cf. +.TP +.B \-h +Output a brief help message. +.TP +.B \-n +The \fIconserver\fP will \fBnot\fP output unloved console output to +stdout. +.TP +.B \-v +Echo the configuration as it is being read (be verbose). +.TP +.B \-V +Output the version of the console server (only) and exit. +.SH EXAMPLES +conserver: expert: login ksb +.br +tyro: panic: my brain hurts +.br +conserver: ksb shifts from expert to tyro +.br +conserver: tyro: logout ksb +.br +\... +.SH FILES +.TS +l l. +/usr/local/lib/conserver.cf description of console terminal lines +/usr/adm/\fIhost\fP.console log files for \fIhost\fP's console +/dev/tty?? terminal line device files +\fIstdout\fP summary of unloved console errors +.TE +.SH AUTHORS +Thomas A. Fine, Ohio State Computer Science +.br +Kevin S Braunsdorf, Purdue University Computing Center +.SH "SEE ALSO" +console(1L), conserver.cf(5L) diff --git a/conserver/conserver.passwd b/conserver/conserver.passwd new file mode 100644 index 0000000..705f94b --- /dev/null +++ b/conserver/conserver.passwd @@ -0,0 +1,4 @@ +bryan:r71mXjfALB5Ak:any +djs:r71mXjfALB5Ak:login +chogan:*passwd*:foobar,login,shell +hogan:*passwd*:any diff --git a/conserver/fallback.c b/conserver/fallback.c new file mode 100644 index 0000000..2eb33dc --- /dev/null +++ b/conserver/fallback.c @@ -0,0 +1,234 @@ +/* + * $Id: fallback.c,v 5.18 1994-07-19 08:25:54-07 ksb Exp $ + * + * This is a fake library interface to ptyd (mtr&ksb) + * + * Mike Rowan (mtr@mace.cc.purdue.edu) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" + +#if HAVE_PTSNAME +/* for grantpt() and unlockpt() (gregf) + */ +#include +#endif + +#if NEED_UNISTD_H +#include +#endif + +#if USE_STRINGS +#include +#else +#include +#endif + +#if DO_VIRTUAL && ! HAVE_PTYD + +extern int errno; +#if !HAVE_STRERROR +extern char *sys_errlist[], *strchr(); +#define strerror(Me) (sys_errlist[Me]) +#endif + + +static char *__pty_host; +static char *__pty_fmt; + +static int iLogPri = LOG_DEBUG; + + +/* + * 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. + */ +#if defined(sun) +static char charone[] = + "prstuvwxyzPQRSTUVWq"; +#else +#if defined(dynix) +static char charone[] = + "prstuvwxyzPQRSTUVWq"; +#else +#if defined(ultrix) +static char charone[] = + "prstuvwxyzPQRSTUVWq"; +#else +/* all the world's a vax ;-) */ +static char charone[] = + "prstuvwxyzPQRSTUVWq"; +#endif +#endif +#endif + +static char chartwo[] = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#if (defined(_AIX) || defined(PTX4)) +static char acMaster[] = + "/dev/ptc/XXXXXXXXX"; +static char acSlave[] = + "/dev/pts/XXXXXXXXX"; +#else +static char acMaster[] = + "/dev/ptyXX"; +static char acSlave[] = + "/dev/ttyXX"; +#endif /* _AIX */ + +#if !HAVE_GETPSEUDO +#ifdef _AIX +/* + * get a pty for the user (emulate the neato sequent call) (mm) + */ +static int +getpseudotty(slave, master) +char **master, **slave; +{ + int fd; + char *pcName, *pcTmp; + + if (0 > (fd = open("/dev/ptc", O_RDWR|O_NDELAY, 0))) { + return -1; + } + if ((char *)0 == (pcName = ttyname(fd))) { + return -1; + } + (void)strcpy(acSlave, pcName); + *slave = acSlave; + + (void)strcpy(acMaster, pcName); + acMaster[7] = 'c'; + *master = acMaster; + + return fd; +} + +#else +#if HAVE_PTSNAME + +/* get a pty for the user -- emulate the neato sequent call under (gregf) + * DYNIX/ptx v4.0 + */ +static int +getpseudotty(slave, master) +char **master, **slave; +{ + int fd; + char *pcName, *pcTmp; + + if (0 > (fd = open("/dev/ptmx", O_RDWR, 0))) { + return -1; + } + grantpt(fd); /* change permission of slave */ + unlockpt(fd); /* unlock slave */ + if ((char *)0 == (pcName = ttyname(fd))) { + return -1; + } + (void)strcpy(acMaster, pcName); + *master = acMaster; + + if ((char *) 0 == (pcName = ptsname(fd))) { + return -1; + } + + (void)strcpy(acSlave, pcName); + *slave = acSlave; + + return fd; +} + +#else +/* + * get a pty for the user (emulate the neato sequent call) (ksb) + */ +static int +getpseudotty(slave, master) +char **master, **slave; +{ + static char *pcOne = charone, *pcTwo = chartwo; + auto int fd, iLoop, iIndex = sizeof("/dev/pty")-1; + auto char *pcOld1; + auto struct stat statBuf; + + iLoop = 0; + pcOld1 = pcOne; + for (;;) { + if ('\000' == *++pcTwo) { + pcTwo = chartwo; + if ('\000' == *++pcOne) { + pcOne = charone; + if (pcOld1 == pcOne && ++iLoop > 1 || iLoop > 32) + return -1; + } + } + acMaster[iIndex] = *pcOne; + acMaster[iIndex+1] = *pcTwo; + + /* + * Remeber we are root - stat the file + * to see if it exists before we open it + * for read/write - if it doesn't we don't + * have any pty's left in the row + */ + if (-1 == stat(acMaster, &statBuf) || S_IFCHR != (statBuf.st_mode&S_IFMT)) { + pcTwo = "l"; + continue; + } + + if (0 > (fd = open(acMaster, O_RDWR|O_NDELAY, 0))) { + continue; + } + acSlave[iIndex] = *pcOne; + acSlave[iIndex+1] = *pcTwo; + if (-1 == access(acSlave, F_OK)) { + (void) close(fd); + continue; + } + break; + } + *master = acMaster; + *slave = acSlave; + return fd; +} +#endif /* PTX version */ +#endif /* _AIX */ +#endif /* !HAVE_GETPSEUDO */ + +/* + * get a Joe pty bacause the daemon is not with us, sadly. (ksb) + */ +int +FallBack(pcSlave, pcMaster) +char *pcSlave, *pcMaster; +{ + auto int fd; + auto char *pcTSlave, *pcTMaster; + + if (-1 == (fd = getpseudotty(& pcTSlave, & pcTMaster))) { + return -1; + } + (void) strcpy(pcSlave, pcTSlave); + (void) strcpy(pcMaster, pcTMaster); + return fd; +} + +#endif /* no code if it is not used */ diff --git a/conserver/group.c b/conserver/group.c new file mode 100644 index 0000000..aa4349a --- /dev/null +++ b/conserver/group.c @@ -0,0 +1,1643 @@ +/* + * $Id: group.c,v 5.48 1998-12-14 11:20:15-08 bryan Exp $ + * + * 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. + * + * + * Copyright 1992 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Recoded 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. + */ +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1990 The Ohio State University.\n\ +@(#) Copyright 1992 Purdue Research Foundation.\n\ +All rights reserved.\n"; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "consent.h" +#include "client.h" +#include "access.h" +#include "group.h" +#include "version.h" +#include "main.h" + +#if DO_VIRTUAL +#if HAVE_PTYD +#include "local/openpty.h" +#else +extern int FallBack(); +#endif /* ptyd */ +#endif /* virtual consoles */ + +#if USE_SYS_TIME_H +#include +#else +#include +#endif +#include + +#if USE_TERMIO +#include + +#else +#if USE_TERMIOS +#include +#include + +#else /* use ioctl stuff */ +#include +#include +#endif +#endif + +#if USE_STREAMS +#include +#endif + +#if USE_STRINGS +#include +#else +#include +#endif + +#include + +#if HAVE_SHADOW +#include +#endif + +extern char *crypt(), *calloc(); +extern time_t time(); + + +/* Is this passwd a match for this user's passwd? (gregf/ksb) + * look up passwd in shadow file if we have to, if we are + * given a special epass try it first. + */ +int +CheckPass(pwd, pcEPass, pcWord) +struct passwd *pwd; +char *pcEPass, *pcWord; +{ +#if HAVE_SHADOW + register struct spwd *spwd; +#endif + + if ((char *)0 != pcEPass && '\000' != pcEPass[0]) { + if (0 == strcmp(pcEPass, crypt(pcWord, pcEPass))) { + return 1; + } + } +#if HAVE_SHADOW + if ('x' == pwd->pw_passwd[0] && '\000' == pwd->pw_passwd[1]) { + if ((struct spwd *)0 != (spwd = getspnam(pwd->pw_name))) + return 0 == strcmp(spwd->sp_pwdp, crypt(pcWord, spwd->sp_pwdp)); + return 0; + } +#endif + return 0 == strcmp(pwd->pw_passwd, crypt(pcWord, pwd->pw_passwd)); +} + +/* on an HUP close and re-open log files so lop can trim them (ksb) + * lucky for us: log file fd's can change async from the group driver! + */ +static GRPENT *pGEHup; +static SIGRETS +ReOpen(arg) + int arg; +{ + register int i; + register CONSENT *pCE; + + if ((GRPENT *)0 == pGEHup) { + return; + } + + for (i = 0, pCE = pGEHup->pCElist; i < pGEHup->imembers; ++i, ++pCE) { + if (-1 == pCE->fdlog) { + continue; + } + (void)close(pCE->fdlog); + if (-1 == (pCE->fdlog = open(pCE->lfile, O_RDWR|O_CREAT|O_APPEND, 0666))) { + CSTROUT(2, "conserver: help! cannot reopen log files!\n"); + continue; + } + } +} + +void +Mark(arg) + int arg; +{ + long tyme; + char acOut[BUFSIZ]; + char styme[26]; + register int i; + register CONSENT *pCE; + + if ((GRPENT *)0 == pGEHup) { + return; + } + + tyme = time((long *)0); + (void)strcpy(styme, ctime(&tyme)); + styme[24] = '\000'; + /* [-- MARK -- `date`] */ + sprintf(acOut, "[-- MARK -- %s]\r\n", styme); + + for (i = 0, pCE = pGEHup->pCElist; i < pGEHup->imembers; ++i, ++pCE) { + if (-1 == pCE->fdlog) { + continue; + } + if ( pCE->nextMark && (tyme >= pCE->nextMark) ) { + (void)write(pCE->fdlog, acOut, strlen(acOut)); + pCE->nextMark = tyme + pCE->mark; + } + } + signal(SIGALRM, Mark); + alarm(ALARMTIME); +} + +#if DO_VIRTUAL +/* on a TERM we have to cleanup utmp entries (ask ptyd to do it) (ksb) + */ +static SIGRETS +DeUtmp(sig) +int sig; +{ + register int i; + register CONSENT *pCE; + + if ((GRPENT *)0 == pGEHup) { + return; + } + + for (i = 0, pCE = pGEHup->pCElist; i < pGEHup->imembers; ++i, ++pCE) { + if (-1 == pCE->fdtty || 0 == pCE->fvirtual) { + continue; + } +#if HAVE_PTYD + (void)closepty(pCE->acslave, pCE->dfile, OPTY_UTMP, pCE->fdlog); +#else + (void)close(pCE->fdlog); +#endif + } + exit(0); + _exit(0); + abort(); + /*NOTREACHED*/ +} + +/* virtual console procs are our kids, when they die we get a CHLD (ksb) + * which will send us here to clean up the exit code. The lack of a + * reader on the pseudo will cause us to notice the death in Kiddie... + */ +static SIGRETS +ReapVirt(sig) +int sig; +{ + register int i, pid; + auto long tyme; + auto WAIT_T UWbuf; + +#if HAVE_WAIT3 + while (-1 != (pid = wait3(& UWbuf, WNOHANG, (struct rusage *)0))) { +#else + while (-1 != (pid = wait(& UWbuf))) { +#endif + if (0 == pid) { + break; + } + /* stopped child is just continuted + */ + if (WIFSTOPPED(UWbuf) && 0 == kill(pid, SIGCONT)) { + continue; + } + } +} +#endif + + +static char acStop[] = { /* buffer for oob stop command */ + OB_SUSP, 0 +}; + +int CheckPasswd(pCLServing, pw_string) +CLIENT *pCLServing; +char *pw_string; +{ + struct passwd *pwd; + FILE *fp; + char buf[100]; + char *server, *servers, *this_pw, *user; + char username[64]; /* same as acid */ +#if HAVE_SHADOW + register struct spwd *spwd; +#endif + + strcpy(username, pCLServing->acid); + if ( user = strchr(username, '@') ) + *user = '\000'; + + if ((fp = fopen(PASSWD_FILE, "r")) == NULL) { + printf("%s: Cannot open passwd file %s: %s\n", + progname, PASSWD_FILE, strerror(errno)); + + if ((struct passwd *)0 == (pwd = getpwuid(0))) { + CSTROUT(pCLServing->fd, "no root passwd?\r\n"); + return 0; + } + if (0 != CheckPass(pwd, pw_string, pCLServing->accmd)) { + if (fVerbose) { + printf("%s: User %s logging into server %s via root or console passwd\n", + progname, pCLServing->acid, pCLServing->pCEwant->server); + } + return 1; + } + } else { +/* printf("Opened passwd file %s\n", PASSWD_FILE);*/ + + while (fgets(buf, sizeof(buf), fp) != NULL) + { + user = strtok(buf, ":\n"); + if (user == NULL) + continue; + if (strcmp(user, username)) + continue; + this_pw = strtok(NULL, ":\n"); + if (strcmp(this_pw, "*passwd*") == 0) { + this_pw = NULL; + if ((struct passwd *)0 != (pwd = getpwnam(user))) { + #if HAVE_SHADOW + if ('x' == pwd->pw_passwd[0] && '\000' == pwd->pw_passwd[1]) { + if ((struct spwd *)0 != (spwd = getspnam(pwd->pw_name))) { + this_pw = spwd->sp_pwdp; + } + } else { + this_pw = pwd->pw_passwd; + } + #else + this_pw = pwd->pw_passwd; + #endif + } + } + if (this_pw == NULL) + continue; + servers = strtok(NULL, ":\n"); + if (servers == NULL) + continue; + + /* + printf("Got servers <%s> passwd <%s> user <%s>, want <%s>\n", + servers, this_pw, user, + pCLServing->pCEwant->server); + */ + + if (strcmp(this_pw, crypt(pCLServing->accmd, this_pw)) == 0) { + server = strtok( servers, "," ); + while ( server ) { /* For each server */ + if (strcmp(server, "any") == 0) { + if (fVerbose) { + printf("%s: User %s logging into server %s\n", + progname, pCLServing->acid, pCLServing->pCEwant->server); + } + fclose(fp); + return 1; + } else { + char *p; + int max; + max = strlen( server ); + p = pCLServing->pCEwant->server; + while ( strlen(p) >= max ) { + if (strcmp(server, p) == 0) { + if (fVerbose) { + printf("%s: User %s logging into server %s\n", + progname, pCLServing->acid, pCLServing->pCEwant->server); + } + fclose(fp); + return 1; + } + if ( domainHack ) { + p = strchr( p, '.' ); + if ((char *)0 == p) { + break; + } + ++p; + } else { + break; + } + } + } + server = strtok( NULL, "," ); + } + } + } + fclose(fp); + } + + return 0; +} + +static char* +IdleTyme( tyme ) +register long tyme; +{ + static char timestr[256]; /* Don't want to overrun the array... */ + register long hours, minutes; + + minutes = tyme / 60; + hours = minutes / 60; + minutes = minutes % 60; + + if ( hours < 24 ) + sprintf( timestr, "%2d:%02d", hours, minutes ); + else if ( hours < 48 ) + sprintf( timestr, "%d day", hours / 24 ); + else + sprintf( timestr, "%ddays", hours / 24 ); + + return timestr; +} + +/* routine used by the child processes. (ksb/fine) + * Most of it is escape sequence parsing. + * fine: + * All of it is squirrely code, for which I most humbly apologize + * ksb: + * Note the states a client can be in, all of the client processing + * is done one character at a time, we buffer and shift a lot -- this + * stops the denial of services attack where a user telnets to the + * group port and just hangs it (by not following the protocol). I've + * repaired this by letting all new clients on a bogus console that is + * a kinda control line for the group. They have to use the `;' + * command to shift to a real console before they can get any (real) + * thrills. + * + * If you were not awake in your finite state machine course this code + * should scare the shit out of you; but there are a few invarients: + * - the fwr (I can write) bit always is set *after* the + * notification that to the console (and reset before) + * - we never look at more than one character at a time, even + * when we read a hunk from the MUX we string it out in a loop + * - look at the output (x, u, w) and attach (a, f, ;) commands + * for more clues + * + * NB: the ZZZ markers below indicate places where I didn't have time + * (machine?) to test some missing bit of tty diddling, I'd love + * patches for other ioctl/termio/termios stuff -- ksb + * + */ +static void +Kiddie(pGE, sfd) +register GRPENT *pGE; +int sfd; +{ + register CLIENT + *pCL, /* console we must scan/notify */ + *pCLServing, /* client we are serving */ + *pCLFree; /* head of free list */ + register CONSENT + *pCEServing, /* console we are talking to */ + *pCE; /* the base of our console list */ + register int iConsole; + register int i, nr; + register struct hostent *hpPeer; + register struct passwd *pwd; + register char *pcPass; + register long tyme; + long tymee; + char stymee[26]; + auto CONSENT CECtl; /* our control `console' */ + auto char cType; + auto int maxfd, so; + auto fd_set rmask, rinit; + auto char acOut[BUFSIZ], acIn[BUFSIZ], acNote[132*2]; + auto CLIENT dude[MAXMEMB]; /* alloc one set per console */ +#if HAVE_RLIMIT + struct rlimit rl; +#endif +#if USE_TERMIO + auto struct sgttyb sty; +#else +#if USE_TERMIOS + auto struct termios sbuf; +#else /* ioctl, like BSD4.2 */ + auto struct sgttyb sty; +#endif +#endif + + + /* turn off signals that master() might turned on + * (only matters if respawned) + */ + (void)signal(SIGURG, SIG_DFL); +#if DO_VIRTUAL + (void)signal(SIGTERM, DeUtmp); + (void)signal(SIGCHLD, ReapVirt); +#else + (void)signal(SIGTERM, SIG_DFL); + (void)signal(SIGCHLD, SIG_DFL); +#endif + + /* setup our local data structures and fields, and contol line + */ + pCE = pGE->pCElist; + for (iConsole = 0; iConsole < pGE->imembers; ++iConsole) { + pCE[iConsole].fup = 0; + pCE[iConsole].pCLon = pCE[iConsole].pCLwr = (CLIENT *)0; +#if DO_VIRTUAL + pCE[iConsole].fdlog = -1; + if (0 == pCE->fvirtual) { + pCE[iConsole].fdtty = -1; + continue; + } + /* open a pty for each vitrual console + */ +#if HAVE_PTYD + pCE[iConsole].fdtty = openpty(pCE[iConsole].acslave, pCE[iConsole].dfile, OPTY_UTMP, 0); +#else /* oops, get ptyd soon */ + /* we won't get a utmp entry... *sigh* + */ + pCE[iConsole].fdtty = FallBack(pCE[iConsole].acslave, pCE[iConsole].dfile); +#endif /* find openpty */ +#else + pCE[iConsole].fdlog = pCE[iConsole].fdtty = -1; +#endif + } + sprintf(CECtl.server, "ctl_%d", pGE->port); + CECtl.inamelen = strlen(CECtl.server); /* bogus, of course */ + CECtl.acline[CECtl.inamelen++] = ':'; + CECtl.acline[CECtl.inamelen++] = ' '; + CECtl.iend = CECtl.inamelen; + (void)strcpy(CECtl.dfile, strcpy(CECtl.lfile, "/dev/null")); + /* below "" gets us the default parity and baud structs + */ + CECtl.pbaud = FindBaud(""); + CECtl.pparity = FindParity(""); + CECtl.fdlog = CECtl.fdtty = -1; + CECtl.fup = 0; + CECtl.pCLon = CECtl.pCLwr = 0; + + /* 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 + * to rmask before we call select, this saves lots of prep work + * we used to do in the loop, but we have to mod rinit whenever + * we add a connection or drop one... (ksb) + */ +#if HAVE_RLIMIT + getrlimit(RLIMIT_NOFILE, &rl); + maxfd = rl.rlim_cur; +#else + maxfd = getdtablesize(); +#endif + FD_ZERO(&rinit); + FD_SET(sfd, &rinit); + /* open all the files we need for the consoles in our group + * if we can't get one (bitch and) flag as down + */ + for (iConsole = 0; iConsole< pGE->imembers; ++iConsole) { + ConsInit(& pCE[iConsole], &rinit); + } + + /* set up the list of free connection slots, we could just calloc + * them, but the stack pages are already in core... + */ + pCLFree = dude; + for (i = 0; i < MAXMEMB-1; ++i) { + dude[i].pCLnext = & dude[i+1]; + } + dude[MAXMEMB-1].pCLnext = (CLIENT *)0; + + /* on a SIGHUP we should close and reopen our log files + */ + pGEHup = pGE; + signal(SIGHUP, ReOpen); + + /* on a SIGALRM we should mark log files */ + signal(SIGALRM, Mark); + alarm(ALARMTIME); + + /* the MAIN loop a group server + */ + pGE->pCLall = (CLIENT *)0; + while (1) { + rmask = rinit; + + if (-1 == select(maxfd, &rmask, (fd_set *)0, (fd_set *)0, (struct timeval *)0)) { + if ( errno != EINTR ) { + fprintf(stderr, "%s: select: %s\n", progname, strerror(errno)); + } + continue; + } + + /* anything from any console? + */ + for (iConsole = 0; iConsole < pGE->imembers; ++iConsole) { + pCEServing = pCE+iConsole; + if (!pCEServing->fup || !FD_ISSET(pCEServing->fdtty, &rmask)) { + continue; + } + /* read terminal line */ + if ((nr = read(pCEServing->fdtty, acIn, sizeof(acIn))) < 0) { + /* carrier lost */ + fprintf(stderr, "%s: lost carrier on %s (%s)!\n", progname, pCEServing->server, pCEServing->dfile); +#if DO_VIRTUAL + if (pCEServing->fvirtual) { + FD_CLR(pCEServing->fdtty, &rinit); + pCEServing->ipid = -1; + pCEServing->fup = 0; + } else { + ConsInit(pCEServing, &rinit); + } +#else + ConsInit(pCEServing, &rinit); +#endif + continue; + } +#if CPARITY + /* clear parity -- the log file looks better this way + */ + for (i = 0; i < nr; ++i) { + acIn[i] &= 127; + } +#endif + + /* log it and write to all connections on this server + */ + if ( !pCEServing->nolog ) { + (void)write(pCEServing->fdlog, acIn, nr); + } + + /* output all console info nobody is attached + */ + if (fAll && (CLIENT *)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; + } + write(1, pCEServing->acline, pCEServing->iend); + pCEServing->iend = pCEServing->inamelen; + } + } + + /* write console info to clients (not suspended) + */ + for (pCL = pCEServing->pCLon; (CLIENT *)0 != pCL; pCL = pCL->pCLnext) { + if (pCL->fcon) { + (void)write(pCL->fd, acIn, nr); + } + } + } + + + /* anything from a connection? + */ + for (pCLServing = pGE->pCLall; (CLIENT *)0 != pCLServing; pCLServing = pCLServing->pCLscan) { + if (!FD_ISSET(pCLServing->fd, &rmask)) { + continue; + } + pCEServing = pCLServing->pCEto; +#if DEBUG + if ((pCLServing->fwr != 0) != (pCEServing->pCLwr == pCLServing)) { + fprintf(stderr, "%s: internal check failed %s on %s\n", progname, pCLServing->acid, pCEServing->server); + } +#endif + /* read connection */ + if ((nr = read(pCLServing->fd, acIn, sizeof(acIn))) == 0) { + /* reached EOF - close connection */ +drop: + /* re-entry point to drop a connection + * (for any other reason) + * log it, drop from select list, + * close gap in table, restart loop + */ + if (&CECtl != pCEServing) { + tymee = time((long *)0); + (void)strcpy(stymee, ctime(&tymee)); + stymee[24] = '\000'; + printf("%s: %s: logout %s [%s]\n", progname, pCEServing->server, pCLServing->acid, stymee); + } + + FD_CLR(pCLServing->fd, &rinit); + (void)close(pCLServing->fd); + pCLServing->fd = -1; + + /* mark as not writer, if he is + * and turn logging back on... + */ + if (pCLServing->fwr) { + pCLServing->fwr = 0; + pCLServing->fwantwr = 0; + if (pCEServing->nolog) { + pCEServing->nolog = 0; + sprintf(acOut, "[Console logging restored (logout)]\r\n"); + (void)write(pCEServing->fdlog, acOut, strlen(acOut)); + } + pCEServing->pCLwr = FindWrite(pCEServing->pCLon); + } + + /* mark as unconnected and remove from both + * lists (all clients, and this console) + */ + pCLServing->fcon = 0; + if ((CLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = pCLServing->ppCLbnext; + } + *(pCLServing->ppCLbnext) = pCLServing->pCLnext; + if ((CLIENT *)0 != pCLServing->pCLscan) { + pCLServing->pCLscan->ppCLbscan = pCLServing->ppCLbscan; + } + *(pCLServing->ppCLbscan) = pCLServing->pCLscan; + + /* the continue below will advance to a (ksb) + * legal client, even though we are now closed + * and in the fre list becasue pCLscan is used + * for the free list + */ + pCLServing->pCLnext = pCLFree; + pCLFree = pCLServing; + continue; + } + + /* update last keystroke time + */ + pCLServing->typetym = tyme = time((long *)0); + + /* always clear parity from the network + */ + for (i = 0; i < nr; ++i) { + acIn[i] &= 127; + } + + for (i = 0; i < nr; ++i) switch (pCLServing->iState) { + case S_IDENT: + /* append chars to acid until white space + */ + if (pCLServing->icursor == sizeof(pCLServing->acid)) { + CSTROUT(pCLServing->fd, "Name too long.\r\n"); + goto drop; + } + if (!isspace(acIn[i])) { + pCLServing->acid[pCLServing->icursor++] = acIn[i]; + continue; + } + if (0 != pCLServing->icursor) { + pCLServing->acid[pCLServing->icursor] = '\000'; + } + pCLServing->icursor = 0; + CSTROUT(pCLServing->fd, "host:\r\n"); + pCLServing->iState = S_HOST; + continue; + + case S_HOST: + /* append char to buffer, check for \n + * continue if incomplete + * else swtich to new host + */ + if (pCLServing->icursor == sizeof(pCLServing->accmd)) { + CSTROUT(pCLServing->fd, "Host too long.\r\n"); + goto drop; + } + if (!isspace(acIn[i])) { + pCLServing->accmd[pCLServing->icursor++] = acIn[i]; + continue; + } + if (0 != pCLServing->icursor) { + pCLServing->accmd[pCLServing->icursor] = '\000'; + } + /* try to move to the given console + */ + pCLServing->pCEwant = (CONSENT *)0; + for (iConsole = 0; iConsole < pGE->imembers; ++iConsole) { + if (0 == strcmp(pCLServing->accmd, pCE[iConsole].server)) { + pCLServing->pCEwant = & pCE[iConsole]; + break; + } + } + if ((CONSENT *)0 == pCLServing->pCEwant) { + for (iConsole = 0; iConsole < pGE->imembers; ++iConsole) { + if (0 == strncmp(pCLServing->accmd, pCE[iConsole].server, strlen(pCLServing->accmd))) { + pCLServing->pCEwant = & pCE[iConsole]; + break; + } + } + } + + if ((CONSENT *)0 == pCLServing->pCEwant) { + sprintf(acOut, "%s: no such console\r\n", pCLServing->accmd); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + goto drop; + } + + pCLServing->icursor = 0; + if ('t' == pCLServing->caccess) { + goto shift_console; + } + CSTROUT(pCLServing->fd, "passwd:\r\n"); + pCLServing->iState = S_PASSWD; + continue; + + case S_PASSWD: + /* gather passwd, check and drop or + * set new state + */ + if (pCLServing->icursor == sizeof(pCLServing->accmd)) { + CSTROUT(pCLServing->fd, "Passwd too long.\r\n"); + goto drop; + } + if ('\n' != acIn[i]) { + pCLServing->accmd[pCLServing->icursor++] = acIn[i]; + continue; + } + pCLServing->accmd[pCLServing->icursor] = '\000'; + if ('\r' == pCLServing->accmd[pCLServing->icursor-1]) { + pCLServing->accmd[--pCLServing->icursor] = '\000'; + } + pCLServing->icursor = 0; + + /* in the CONFIG file gave this group a + * password use it before root's + * password (for malowany) + */ +/* + if ((struct passwd *)0 == (pwd = getpwuid(0))) { + CSTROUT(pCLServing->fd, "no root passwd?\r\n"); + goto drop; + } + if (0 == CheckPass(pwd, pGE->passwd, pCLServing->accmd)) { +}*/ + if (0 == CheckPasswd( pCLServing, pGE->passwd)) { + CSTROUT(pCLServing->fd, "Sorry.\r\n"); + printf("%s: %s: %s: bad passwd\n", progname, pCLServing->pCEwant->server, pCLServing->acid); + goto drop; + } + shift_console: + /* remove from current host + */ + if ((CLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = pCLServing->ppCLbnext; + } + *(pCLServing->ppCLbnext) = pCLServing->pCLnext; + if (pCLServing->fwr) { + pCLServing->fwr = 0; + pCLServing->fwantwr = 0; + pCEServing->pCLwr = FindWrite(pCEServing->pCLon); + } + + /* inform operators of the change + */ +/* if (fVerbose) { */ + tymee = time((long *)0); + (void)strcpy(stymee, ctime(&tymee)); + stymee[24] = '\000'; + if (&CECtl == pCEServing) { + printf("%s: %s: login %s [%s]\n", progname, pCLServing->pCEwant->server, pCLServing->acid, stymee); + } else { + printf("%s: %s moves from %s to %s [%s]\n", progname, pCLServing->acid, pCEServing->server, pCLServing->pCEwant->server, stymee); + } +/* } */ + + /* set new host and link into new host list + */ + pCEServing = pCLServing->pCEwant; + pCLServing->pCEto = pCEServing; + pCLServing->pCLnext = pCEServing->pCLon; + pCLServing->ppCLbnext = & pCEServing->pCLon; + if ((CLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = & pCLServing->pCLnext; + } + pCEServing->pCLon = pCLServing; + + /* try for attach on new console + */ + if (!pCEServing->fup) { + CSTROUT(pCLServing->fd, "line to host is down]\r\n"); + } else if (pCEServing->fronly) { + CSTROUT(pCLServing->fd, "host is read-only]\r\n"); + } else if ((CLIENT *)0 == pCEServing->pCLwr) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + CSTROUT(pCLServing->fd, "attached]\r\n"); + /* this keeps the ops console neat */ + pCEServing->iend = pCEServing->inamelen; + } else { + CSTROUT(pCLServing->fd, "spy]\r\n"); + } + pCLServing->fcon = 1; + pCLServing->iState = S_NORMAL; + continue; + + case S_QUOTE: /* send octal code */ + /* must type in 3 octal digits */ + if (isdigit(acIn[i])) { + pCLServing->accmd[0] *= 8; + pCLServing->accmd[0] += acIn[i] - '0'; + if (++(pCLServing->icursor) < 3) { + write(pCLServing->fd, &acIn[i], 1); + continue; + } + pCLServing->accmd[1] = acIn[i]; + pCLServing->accmd[2] = ']'; + write(pCLServing->fd, pCLServing->accmd+1, 2); + (void)write(pCEServing->fdtty, pCLServing->accmd, 1); + } else { + CSTROUT(pCLServing->fd, " aborted]\r\n"); + } + pCLServing->iState = S_NORMAL; + continue; + + case S_SUSP: + if (!pCEServing->fup) { + CSTROUT(pCLServing->fd, " -- line down]\r\n"); + } else if (pCEServing->fronly) { + CSTROUT(pCLServing->fd, " -- read-only]\r\n"); + } else if ((CLIENT *)0 == pCEServing->pCLwr) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + if ( pCEServing->nolog ) { + CSTROUT(pCLServing->fd, " -- attached (nologging)]\r\n"); + } else { + CSTROUT(pCLServing->fd, " -- attached]\r\n"); + } + } else { + CSTROUT(pCLServing->fd, " -- spy mode]\r\n"); + } + pCLServing->fcon = 1; + pCLServing->iState = S_NORMAL; + continue; + + case S_NORMAL: + /* if it is an escape sequence shift states + */ + if (acIn[i] == pCLServing->ic[0]) { + pCLServing->iState = S_ESC1; + continue; + } + /* if we can write, write to slave tty + */ + if (pCLServing->fwr) { + (void)write(pCEServing->fdtty, &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]) { + static char acA1[16], acA2[16]; + sprintf(acOut, "[read-only -- use %s %s ? for help]\r\n", FmtCtl(pCLServing->ic[0], acA1), FmtCtl(pCLServing->ic[1], acA2)); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + } + continue; + + case S_HALT1: /* halt sequence? */ + pCLServing->iState = S_NORMAL; + if (acIn[i] != '1') { + CSTROUT(pCLServing->fd, "aborted]\r\n"); + continue; + } + + /* send a break + */ + if (pCEServing->isNetworkConsole) + { + char haltseq[2]; + + haltseq[0] = IAC; + haltseq[1] = BREAK; + write(pCEServing->fdtty, haltseq, 2); + } + else + { +#if USE_TERMIO + if (-1 == ioctl(pCEServing->fdtty, TCSBRK, (char *)0)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } +#else +#if USE_TERMIOS || USE_TCBREAK + CSTROUT(pCLServing->fd, "- "); + if (-1 == tcsendbreak(pCEServing->fdtty, 9)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } +#else + if (-1 == ioctl(pCEServing->fdtty, TIOCSBRK, (char *)0)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } + CSTROUT(pCLServing->fd, "- "); + sleep(3); + if (-1 == ioctl(pCEServing->fdtty, TIOCCBRK, (char *)0)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } +#endif +#endif + } + CSTROUT(pCLServing->fd, "sent]\r\n"); + continue; + + case S_CATTN: /* redef escape sequence? */ + pCLServing->ic[0] = acIn[i]; + sprintf(acOut, "%s ", FmtCtl(acIn[i], pCLServing->accmd)); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + pCLServing->iState = S_CESC; + continue; + + case S_CESC: /* escape sequent 2 */ + pCLServing->ic[1] = acIn[i]; + pCLServing->iState = S_NORMAL; + sprintf(acOut, "%s ok]\r\n", FmtCtl(acIn[i], pCLServing->accmd)); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + continue; + + case S_ESC1: /* first char in escape sequence */ + if (acIn[i] == pCLServing->ic[1]) { + if (pCLServing->fecho) + CSTROUT(pCLServing->fd, "\r\n["); + else + CSTROUT(pCLServing->fd, "["); + pCLServing->iState = S_CMD; + continue; + } + /* ^E^Ec or ^_^_^[ + * pass first ^E (^_) and stay in same state + */ + if (acIn[i] == pCLServing->ic[0]) { + if (pCLServing->fwr) { + (void)write(pCEServing->fdtty, pCLServing->ic, 1); + } + continue; + } + /* ^Ex or ^_x + * pass both characters to slave tty + */ + pCLServing->iState = S_NORMAL; + if (pCLServing->fwr) { + (void)write(pCEServing->fdtty, pCLServing->ic, 1); + (void)write(pCEServing->fdtty, &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])) + CSTROUT(pCLServing->fd, "drop line]\r\n"); + else + CSTROUT(pCLServing->fd, "no drop line]\r\n"); + break; + + case ';': /* ;login: */ + CSTROUT(pCLServing->fd, "login:\r\n"); + pCLServing->iState = S_IDENT; + break; + + case 'a': /* attach */ + case 'A': + if (&CECtl == pCEServing) { + sprintf(acOut, "no -- on ctl]\r\n"); + } else if (!pCEServing->fup) { + sprintf(acOut, "line to host is down]\r\n"); + } else if (pCEServing->fronly) { + sprintf(acOut, "host is read-only]\r\n"); + } else if ((CLIENT *)0 == (pCL = pCEServing->pCLwr)) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + if ( pCEServing->nolog ) { + sprintf(acOut, "attached (nologging)]\r\n"); + } else { + sprintf(acOut, "attached]\r\n"); + } + } else if (pCL == pCLServing) { + if ( pCEServing->nolog ) { + sprintf(acOut, "ok (nologging)]\r\n", pCL->acid); + } else { + sprintf(acOut, "ok]\r\n", pCL->acid); + } + } else { + pCLServing->fwantwr = 1; + sprintf(acOut, "no, %s is attached]\r\n", pCL->acid); + } + (void)write(pCLServing->fd, acOut, strlen(acOut)); + break; + + case 'c': + case 'C': +#if USE_TERMIOS + if (-1 == tcgetattr(pCEServing->fdtty, & sbuf)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } + if (0 != (sbuf.c_iflag & IXOFF)) { + sbuf.c_iflag &= ~(IXOFF|IXON); + CSTROUT(pCLServing->fd, "flow OFF]\r\n"); + } else { + sbuf.c_iflag |= IXOFF|IXON; + CSTROUT(pCLServing->fd, "flow ON]\r\n"); + } + if (-1 == tcsetattr(pCEServing->fdtty, TCSANOW, & sbuf)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } +#else + if (-1 == ioctl(pCEServing->fdtty, TIOCGETP, (char *)&sty)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + break; + } + if (0 != (sty.sg_flags & TANDEM)) { + sty.sg_flags &= ~TANDEM; + CSTROUT(pCLServing->fd, "flow OFF]\r\n"); + } else { + sty.sg_flags |= TANDEM; + CSTROUT(pCLServing->fd, "flow ON]\r\n"); + } + (void)ioctl(pCEServing->fdtty, TIOCSETP, (char *)&sty); +#endif + break; + + case 'd': /* down a console */ + case 'D': + if (&CECtl == pCEServing) { + CSTROUT(pCLServing->fd, "no -- on ctl]\r\n"); + continue; + } + if (!pCLServing->fwr && !pCEServing->fronly) { + CSTROUT(pCLServing->fd, "attach to down line]\r\n"); + break; + } + if (!pCEServing->fup) { + CSTROUT(pCLServing->fd, "ok]\r\n"); + break; + } + + pCLServing->fwr = 0; + pCEServing->pCLwr = (CLIENT *)0; + ConsDown(pCEServing, &rinit); + CSTROUT(pCLServing->fd, "line down]\r\n"); + + /* tell all who closed it */ + sprintf(acOut, "[line down by %s]\r\n", pCLServing->acid); + for (pCL = pCEServing->pCLon; (CLIENT *)0 != pCL; pCL = pCL->pCLnext) { + if (pCL == pCLServing) + continue; + if (pCL->fcon) { + (void)write(pCL->fd, acOut, strlen(acOut)); + } + } + break; + + case 'e': /* redefine escape keys */ + case 'E': + pCLServing->iState = S_CATTN; + CSTROUT(pCLServing->fd, "redef: "); + break; + + case 'f': /* force attach */ + case 'F': + if (&CECtl == pCEServing) { + CSTROUT(pCLServing->fd, "no -- on ctl]\r\n"); + continue; + } else if (pCEServing->fronly) { + CSTROUT(pCLServing->fd, "host is read-only]\r\n"); + continue; + } else if (!pCEServing->fup) { + CSTROUT(pCLServing->fd, "line to host is down]\r\n"); + continue; + } + if ( pCEServing->nolog ) { + sprintf(acOut, "attached (nologging)]\r\n"); + } else { + sprintf(acOut, "attached]\r\n"); + } + if ((CLIENT *)0 != (pCL = pCEServing->pCLwr)) { + if (pCL == pCLServing) { + if ( pCEServing->nolog ) { + CSTROUT(pCLServing->fd, "ok (nologging)]\r\n"); + } else { + CSTROUT(pCLServing->fd, "ok]\r\n"); + } + break; + } + pCL->fwr = 0; + pCL->fwantwr = 1; + if ( pCEServing->nolog ) { + sprintf(acOut, "bumped %s (nologging)]\r\n", pCL->acid); + } else { + sprintf(acOut, "bumped %s]\r\n", pCL->acid); + } + sprintf(acNote, "\r\n[forced to `spy\' mode by %s]\r\n", pCLServing->acid); + (void)write(pCL->fd, acNote, strlen(acNote)); + } + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + (void)write(pCLServing->fd, acOut, strlen(acOut)); + break; + + case 'g': /* group info */ + case 'G': + /* we do not show the ctl console + * else we'd get the client always + */ + sprintf(acOut, "group %s]\r\n", CECtl.server); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + for (pCL = pGE->pCLall; (CLIENT *)0 != pCL; pCL = pCL->pCLscan) { + if (&CECtl == pCL->pCEto) + continue; + sprintf(acOut, " %-24.24s %c %-7.7s %5s %.32s\r\n", pCL->acid, pCL == pCLServing ? '*' : ' ', pCL->fcon ? (pCL->fwr ? "attach" : "spy") : "stopped", IdleTyme(tyme - pCL->typetym), pCL->pCEto->server); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + } + break; + + case 'P': /* DEC vt100 pf1 */ + case 'h': /* help */ + case 'H': + case '?': + HelpUser(pCLServing); + break; + +#if HAVE_IDENTD + case 'I': /* identd auth request */ + case 'i': + CSTROUT(pCLServing->fd, "ident"); + IdentifyMe(pCLServing, pCEServing); + switch (pCLServing->caccess) { + case 'a': + CSTROUT(pCLServing->fd, " allowerd]\r\n"); + break; + case 'r': + CSTROUT(pCLServing->fd, " refused]\r\n"); + break; + case 't': + CSTROUT(pCLServing->fd, " trusted]\r\n"); + break; + default: + CSTROUT(pCLServing->fd, " failed]\r\n"); + break; + } + break; +#endif + case 'L': + if (pCLServing->fwr) { + pCEServing->nolog = !pCEServing->nolog; + if ( pCEServing->nolog ) { + CSTROUT(pCLServing->fd, "logging off]\r\n"); + sprintf(acOut, "[Console logging disabled by %s]\r\n", pCLServing->acid); + (void)write(pCEServing->fdlog, acOut, strlen(acOut)); + } else { + CSTROUT(pCLServing->fd, "logging on]\r\n"); + sprintf(acOut, "[Console logging restored by %s]\r\n", pCLServing->acid); + (void)write(pCEServing->fdlog, acOut, strlen(acOut)); + } + } else { + static char acA1[16], acA2[16]; + sprintf(acOut, "read-only -- use %s %s ? for help]\r\n", FmtCtl(pCLServing->ic[0], acA1), FmtCtl(pCLServing->ic[1], acA2)); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + } + break; + + case 'l': /* halt character 1 */ + if (pCEServing->fronly) { + CSTROUT(pCLServing->fd, "can\'t halt read-only host]\r\n"); + continue; + } + if (!pCLServing->fwr) { + CSTROUT(pCLServing->fd, "attach to halt]\r\n"); + continue; + } + pCLServing->iState = S_HALT1; + CSTROUT(pCLServing->fd, "halt "); + break; + + case 'o': /* close and re-open line */ + case 'O': + if (&CECtl == pCEServing) { + CSTROUT(pCLServing->fd, "no -- on ctl]\r\n"); + continue; + } + /* with a close/re-open we might + * change fd's + */ + ConsInit(pCEServing, &rinit); + if (!pCEServing->fup) { + sprintf(acOut, "line to host is still down]\r\n"); + } else if (pCEServing->fronly) { + sprintf(acOut, "up read-only]\r\n"); + } else if ((CLIENT *)0 == (pCL = pCEServing->pCLwr)) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + sprintf(acOut, "up -- attached]\r\n"); + } else if (pCL == pCLServing) { + sprintf(acOut, "up]\r\n", pCL->acid); + } else { + sprintf(acOut, "up, %s is attached]\r\n", pCL->acid); + } + (void)write(pCLServing->fd, acOut, strlen(acOut)); + break; + + case '\022': /* ^R */ + CSTROUT(pCLServing->fd, "^R]\r\n"); + if (pCEServing->iend == pCEServing->inamelen) { + Replay(pCEServing->fdlog, pCLServing->fd, 1); + } else { + write(pCLServing->fd, pCEServing->acline+pCEServing->inamelen , pCEServing->iend-pCEServing->inamelen); + } + break; + + case 'R': /* DEC vt100 pf3 */ + case 'r': /* replay 20 lines */ + CSTROUT(pCLServing->fd, "replay]\r\n"); + Replay(pCEServing->fdlog, pCLServing->fd, 20); + break; + + case 'p': /* replay 60 lines */ + CSTROUT(pCLServing->fd, "long replay]\r\n"); + Replay(pCEServing->fdlog, pCLServing->fd, 60); + break; + + case 'S': /* DEC vt100 pf4 */ + case 's': /* spy mode */ + pCLServing->fwantwr = 0; + if (!pCLServing->fwr) { + CSTROUT(pCLServing->fd, "ok]\r\n"); + break; + } + pCLServing->fwr = 0; + pCEServing->pCLwr = FindWrite(pCEServing->pCLon); + CSTROUT(pCLServing->fd, "spying]\r\n"); + break; + + case 'u': /* hosts on server this */ + case 'U': + CSTROUT(pCLServing->fd, "hosts]\r\n"); + for (iConsole = 0; iConsole < pGE->imembers; ++iConsole) { + sprintf(acOut, " %-24.24s %c %-4.4s %-.40s\r\n", pCE[iConsole].server, pCE+iConsole == pCEServing ? '*' : ' ', pCE[iConsole].fup ? "up" : "down", pCE[iConsole].pCLwr ? pCE[iConsole].pCLwr->acid : pCE[iConsole].pCLon ? "" : ""); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + } + break; + + case 'v': /* version */ + case 'V': + sprintf(acOut, "version `%s\']\r\n", GNAC_VERSION); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + break; + + case 'w': /* who */ + case 'W': + sprintf(acOut, "who %s]\r\n", pCEServing->server); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + for (pCL = pCEServing->pCLon; (CLIENT *)0 != pCL; pCL = pCL->pCLnext) { + sprintf(acOut, " %-24.24s %c %-7.7s %5s %s\r\n", pCL->acid, pCL == pCLServing ? '*' : ' ', pCL->fcon ? (pCL->fwr ? "attach" : "spy") : "stopped", IdleTyme(tyme - pCL->typetym), pCL->actym); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + } + break; + + case 'x': + case 'X': + CSTROUT(pCLServing->fd, "examine]\r\n"); + for (iConsole = 0; iConsole < pGE->imembers; ++iConsole) { + sprintf(acOut, " %-24.24s on %-32.32s at %5.5s%c\r\n", pCE[iConsole].server, pCE[iConsole].dfile, pCE[iConsole].pbaud->acrate, pCE[iConsole].pparity->ckey); + (void)write(pCLServing->fd, acOut, strlen(acOut)); + } + break; + + case 'z': /* suspend the client */ + case 'Z': + case '\032': + if (1 != send(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 = (CLIENT *)0; + } + break; + + case '\t': /* toggle tab expand */ + CSTROUT(pCLServing->fd, "tabs]\r\n"); +#if USE_TERMIO + /* ZZZ */ +#else +#if USE_TERMIOS + if (-1 == tcgetattr(pCEServing->fdtty, & sbuf)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + 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)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } +#else + /* ZZZ */ +#endif +#endif + break; + + case 'Q': /* DEC vt100 PF2 */ + case '.': /* disconnect */ + case '\004': + case '\003': + CSTROUT(pCLServing->fd, "disconnect]\r\n"); + nr = 0; + if (!pCEServing->fup) { + goto drop; + } + if (pCEServing->isNetworkConsole) { + goto drop; + } +#if USE_TERMIOS + if (-1 == tcgetattr(pCEServing->fdtty, & sbuf)) { + CSTROUT(pCLServing->fd, "failed]\r\n"); + continue; + } + if (0 == (sbuf.c_iflag & IXOFF)) { + sbuf.c_iflag |= IXOFF|IXON; + (void)tcsetattr(pCEServing->fdtty, TCSANOW, & sbuf); + } +#else + if (-1 != ioctl(pCEServing->fdtty, TIOCGETP, (char *)&sty) && 0 == (sty.sg_flags & TANDEM)) { + sty.sg_flags |= TANDEM; + (void)ioctl(pCEServing->fdtty, TIOCSETP, (char *)&sty); + } +#endif + goto drop; + + case ' ': /* abort escape sequence */ + case '\n': + case '\r': + CSTROUT(pCLServing->fd, "ignored]\r\n"); + break; + + case '\\': /* quote mode (send ^Q,^S) */ + if (pCEServing->fronly) { + CSTROUT(pCLServing->fd, "can\'t write to read-only host]\r\n"); + continue; + } + if (!pCLServing->fwr) { + CSTROUT(pCLServing->fd, "attach to send character]\r\n"); + continue; + } + pCLServing->icursor = 0; + pCLServing->accmd[0] = '\000'; + pCLServing->iState = S_QUOTE; + CSTROUT(pCLServing->fd, "quote \\"); + break; + default: /* unknown sequence */ + CSTROUT(pCLServing->fd, "unknown -- use `?\']\r\n"); + break; + } + continue; + } + } + + + /* if nothing on control line, get more + */ + if (!FD_ISSET(sfd, &rmask)) { + continue; + } + + /* accept new connections and deal with them + */ + so = sizeof(struct sockaddr_in); + pCLFree->fd = accept(sfd, (struct sockaddr *)&pCLFree->cnct_port, &so); + if (pCLFree->fd < 0) { + fprintf(stderr, "%s: accept: %s\n", progname, strerror(errno)); + continue; + } + + /* We use this information to verify (ksb) + * the source machine as being local. + */ + so = sizeof(in_port); + if (-1 == getpeername(pCLFree->fd, (struct sockaddr *)&in_port, &so)) { + CSTROUT(pCLFree->fd, "getpeername failed\r\n"); + (void)close(pCLFree->fd); + continue; + } + so = sizeof(in_port.sin_addr); + if ((struct hostent *)0 == (hpPeer = gethostbyaddr((char *)&in_port.sin_addr, so, AF_INET))) { + CSTROUT(pCLFree->fd, "unknown peer name\r\n"); + (void)close(pCLFree->fd); + continue; + } + if ('r' == (cType = AccType(hpPeer))) { + CSTROUT(pCLFree->fd, "access from your host refused\r\n"); + (void)close(pCLFree->fd); + continue; + } + + /* save pCL so we can advance to the next free one + */ + pCL = pCLFree; + pCLFree = pCL->pCLnext; + + /* init the identification stuff + */ + sprintf(pCL->acid, "client@%.*s", sizeof(pCL->acid)-10, hpPeer->h_name); + pCL->typetym = pCL->tym = time((long *)0); + (void)strcpy(pCL->actym, ctime(&(pCL->tym))); + pCL->actym[24] = '\000'; + + /* link into the control list for the dummy console + */ + pCL->pCEto = & CECtl; + pCL->pCLnext = CECtl.pCLon; + pCL->ppCLbnext = & CECtl.pCLon; + if ((CLIENT *)0 != pCL->pCLnext) { + pCL->pCLnext->ppCLbnext = & pCL->pCLnext; + } + CECtl.pCLon = pCL; + + /* link into all clients list + */ + pCL->pCLscan = pGE->pCLall; + pCL->ppCLbscan = & pGE->pCLall; + if ((CLIENT *)0 != pCL->pCLscan) { + pCL->pCLscan->ppCLbscan = & pCL->pCLscan; + } + pGE->pCLall = pCL; + + FD_SET(pCL->fd, &rinit); + + /* init the fsm + */ + pCL->fecho = 0; + pCL->iState = S_NORMAL; + pCL->ic[0] = DEFATTN; + pCL->ic[1] = DEFESC; + pCL->caccess = cType; + pCL->icursor = 0; + + /* mark as stopped (no output from console) + * and spy only (on chars to console) + */ + pCL->fcon = 0; + pCL->fwr = 0; + pCL->fwantwr = 0; + CSTROUT(pCL->fd, "ok\r\n"); + + /* remove from the free list + * if we ran out of static connections calloc some... + */ + if ((CLIENT *)0 == pCLFree) { + pCLFree = (CLIENT *)calloc(2, sizeof(CLIENT)); + if ((CLIENT *)0 == pCLFree) { + CSTROUT(2, "no memory in console server, help\n"); + } else { + pCLFree->pCLnext = &pCLFree[1]; + } + } + } +} + +/* create a child process: (fine) + * fork off a process for each group with an open socket for connections + */ +void +Spawn(pGE) +GRPENT *pGE; +{ + register int pid, sfd; + auto int so; + struct sockaddr_in lstn_port; + int true = 1; + + /* get a socket for listening + */ +#if USE_STRINGS + (void)bzero((char *)&lstn_port, sizeof(lstn_port)); +#else + (void)memset((void *)&lstn_port, 0, sizeof(lstn_port)); +#endif + lstn_port.sin_family = AF_INET; + *(u_long *)&lstn_port.sin_addr = INADDR_ANY; + lstn_port.sin_port = 0; + + /* create a socket to listen on + * (prepared by master so he can see the port number of the kid) + */ + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "%s: socket: %s\n", progname, strerror(errno)); + exit(9); + } +#if HAVE_SETSOCKOPT + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, sizeof(true))<0) { + fprintf(stderr, "%s: setsockopt: %s\n", progname, strerror(errno)); + exit(9); + } +#endif + if (bind(sfd, (struct sockaddr *)&lstn_port, sizeof(lstn_port))<0) { + fprintf(stderr, "%s: bind: %s\n", progname, strerror(errno)); + exit(9); + } + so = sizeof(lstn_port); + + if (-1 == getsockname(sfd, (struct sockaddr *)&lstn_port, &so)) { + fprintf(stderr, "%s: getsockname: %s\n", progname, strerror(errno)); + exit(9); + } + pGE->port = lstn_port.sin_port; + + (void)fflush(stderr); + (void)fflush(stdout); + switch (pid = fork()) { + case -1: + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + exit(1); + default: + (void)close(sfd); + pGE->pid = pid; + return; + case 0: + sleep(1); /* pause to let master get ready */ + break; + } + if (listen(sfd, SOMAXCONN) < 0) { + fprintf(stderr, "%s: listen: %s\n", progname, strerror(errno)); + exit(9); + } + Kiddie(pGE, sfd); + + /* should never get here... + */ + (void)close(sfd); + fprintf(stderr, "%s: internal flow error\n", progname); + exit(1); + /*NOTREACHED*/ +} + diff --git a/conserver/group.h b/conserver/group.h new file mode 100644 index 0000000..a75f235 --- /dev/null +++ b/conserver/group.h @@ -0,0 +1,42 @@ +/* + * $Id: group.h,v 5.8 1994-07-19 09:40:23-07 ksb Exp $ + * + * 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. + */ + +#define MAXPSWDLEN 16 /* max length of encrypted password */ + +typedef struct grpent { /* group info */ + int port; /* port group listens on */ + int pid; /* pid of server for group */ + int imembers; /* number of consoles in this group */ + CONSENT *pCElist; /* list of consoles in this group */ + CLIENT *pCLall; /* all clients to scan after select */ + char passwd[MAXPSWDLEN];/* encrypted password for this group */ +} GRPENT; + + +extern void Spawn(); +extern int CheckPass(); diff --git a/conserver/identd.c b/conserver/identd.c new file mode 100644 index 0000000..01e055e --- /dev/null +++ b/conserver/identd.c @@ -0,0 +1,179 @@ +/*@Header@*/ +/* + * ident_client.c + * + * Identifies the remote user of a given connection. + * + * Written 940112 by Luke Mewburn + * + * Copyright (C) 1994 by Luke Mewburn. + * This code may be used freely by anyone as long as this copyright remains. + * + * $Compile(*): ${cc-cc} ${cc_debug--g} -DTEST %f -o %F -lsocket -lnls + */ +#include +#include +#include +#include +#include +#include + +#include "identd.h" + +#define IDENT_PORT 113 + + +/*@Explode cli@*/ +/* (lm) + * ident_client + * - user interface to identd + * + * Args: + * peeraddr sockaddr_in struct of peer end, from getpeername(...) + * ouraddr sockaddr_in struct of local end, from getsockname(...) + * + * Returns: + * NULL on failure to identify (for whatever reason), or pointer to + * static character string with the identity. + */ +char * +ident_client(peeraddr, ouraddr, identifier) + struct sockaddr_in peeraddr, ouraddr; + char *identifier/*[1024]*/; +{ + struct sockaddr_in authcon; + int authfd, authlen; + struct servent *identserv; + int identport; + + FILE *authfpin, *authfpout; + char buffer[8192]; /* XXX: argh! magic numbers */ + char reply_type[81]; + char opsys_or_err[81]; + int rport, lport; + + + authfd = socket(AF_INET, SOCK_STREAM, 0); + if (authfd == -1) + return NULL; + + identserv = getservbyname("ident", "tcp"); + if (identserv) + identport = identserv->s_port; + else + identport = ntohs(IDENT_PORT); + + memset(&authcon, 0, sizeof(authcon)); + authcon.sin_family = AF_INET; + authcon.sin_addr.s_addr = peeraddr.sin_addr.s_addr; + authcon.sin_port = identport; + + authlen = sizeof(authcon); + if (connect(authfd, (struct sockaddr *)&authcon, authlen) < 0) + return NULL; + + authfpin = fdopen(authfd, "r"); + authfpout = fdopen(authfd, "w"); + if (!authfpin || !authfpout) + return NULL; + + fprintf(authfpout, "%d , %d\n", peeraddr.sin_port, ouraddr.sin_port); + fflush(authfpout); + + if (fgets(buffer, sizeof(buffer)-1, authfpin) == NULL) + return NULL; + + shutdown(authfd, 1); + + authlen = sscanf(buffer, "%d , %d : %[^ \t\n\r:] : %[^ \t\n\r:] : %[^\n\r]", + &lport, &rport, reply_type, opsys_or_err, identifier); + if (authlen < 3) + return NULL; + + if (0 == strcasecmp(reply_type, "ERROR")) { + printf("error %s\n", buffer); + return NULL; + } + if (0 != strcasecmp(reply_type, "USERID")) { + printf("no-user %s\n", buffer); + return NULL; + } + + return identifier; +} /* ident_client */ + +/*@Remove@*/ +#if defined(TEST) + +/*@Explode main@*/ +extern int errno; +extern char *sys_errlist[]; +#define strerror(Me) (sys_errlist[Me]) + +static struct sockaddr_in master_port, response_port; + +char *progname = "identd-test"; + +/* test driver for the identd client module (ksb) + * bind to a port, wait for telnets and tell them who they are + */ +int +main(argc, argv, envp) +int argc; +char **argv, **envp; +{ + auto struct sockaddr_in hisaddr, ouraddr; + register int mfd, cfd; + auto int true = 1, length, so; + auto char them[1024]; + + (void)memset((void *)&master_port, 0, sizeof(master_port)); + master_port.sin_family = AF_INET; + *(u_long *)&master_port.sin_addr = INADDR_ANY; + master_port.sin_port = htons(7098); + + if (-1 == (mfd = socket(AF_INET, SOCK_STREAM, 0))) { + fprintf(stderr, "%s: socket: %s\n", progname, strerror(errno)); + exit(1); + } +#if defined(SO_REUSEADDR) && defined(SOL_SOCKET) + if (setsockopt(mfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, sizeof(true)) < 0) { + fprintf(stderr, "%s: setsockopt: %s\n", progname, strerror(errno)); + exit(1); + } +#endif + if (bind(mfd, (struct sockaddr *)&master_port, sizeof(master_port))<0) { + fprintf(stderr, "%s: bind: %s\n", progname, strerror(errno)); + exit(1); + } + + if (listen(mfd, SOMAXCONN) < 0) { + fprintf(stderr, "%s: listen: %s\n", progname, strerror(errno)); + exit(1); + } + + length = sizeof(ouraddr); + if (getsockname(mfd, (struct sockaddr *)&ouraddr, &length) < 0) { + fprintf(stderr, "%s: getsockname: %d: %s\n", progname, mfd, strerror(errno)); + + } + + while (so = sizeof(response_port), -1 != (cfd = accept(mfd, (struct sockaddr *)&response_port, &so))) { + printf("%d\n", cfd); + length = sizeof(hisaddr); + if (getpeername(cfd, (struct sockaddr *)&hisaddr, &length) < 0) { + write(cfd, "can't get your addrees?\n", 24); + } else if ((char *)0 != ident_client(hisaddr, ouraddr, them)) { + write(cfd, them, strlen(them)); + write(cfd, "\n", 1); + } else { + write(cfd, "no identd?\n", 11); + } + close(cfd); + printf("closed\n"); + } + + exit(0); +} +/*@Remove@*/ +#endif /* test driver */ diff --git a/conserver/init.script b/conserver/init.script new file mode 100755 index 0000000..1252bfc --- /dev/null +++ b/conserver/init.script @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Startup for conserver +# + +PATH=/usr/bin:/usr/local/bin + +case "$1" in + 'start') + LF=/var/log/conserver.log + echo "Starting console server daemon" + [ -f $LF ] && mv $LF $LF.old + conserver -n -d > $LF 2>&1 + ;; + + 'stop') + master=`ps -ef | grep conserver | awk '$3 == "1"{print $2}'` + [ "$master" ] && kill -TERM $master + ;; + + *) + echo "Usage: $0 { start | stop }" + ;; + +esac +exit 0 diff --git a/conserver/main.c b/conserver/main.c new file mode 100644 index 0000000..58d8ce4 --- /dev/null +++ b/conserver/main.c @@ -0,0 +1,380 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "consent.h" +#include "client.h" +#include "group.h" +#include "master.h" +#include "access.h" +#include "readcfg.h" +#include "version.h" +#if USE_STRINGS +#include +#else +#include +#endif + +char rcsid[] = + "$Id: main.c,v 5.27 1998-11-19 14:32:45-08 bryan Exp $"; +char *progname = + rcsid; +int fAll = 1, fVerbose = 0, fSoftcar = 0; +int fDaemon = 0; +char chDefAcc = 'r'; +char *pcConfig = CONFIG; +int domainHack = 0; + +#if defined(SERVICE) +char acService[] = SERVICE; +#endif + +struct sockaddr_in in_port; +char acMyAddr[4]; /* "\200\76\7\1" */ +char acMyHost[256]; /* staff.cc.purdue.edu */ + +/* become a daemon (ksb) + */ +static void +daemonize() +{ + int res, td; + + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); +#if defined(SIGTTOU) + (void) signal(SIGTTOU, SIG_IGN); +#endif +#if defined(SIGTSTP) + (void) signal(SIGTSTP, SIG_IGN); +#endif + + switch (res = fork()) { + case -1: + (void) fprintf(stderr, "%s: fork: %m\n", progname, strerror(errno)); + exit(1); + case 0: + break; + default: + sleep(1); + exit(0); + } + + /* if we read from stdin (by accident) we don't wanna block + */ + close(0); + if (0 != open("/dev/null", 2, 0644)) { + fprintf(stderr, "%s: open: /dev/null: %s\n", progname, strerror(errno)); + exit(1); + } + + /* Further disassociate this process from the terminal + * Maybe this will allow you to start a daemon from rsh, + * i.e. with no controlling terminal. + */ +#if HAVE_SETSID + (void)setsid(); +#else + (void) setpgrp(0, getpid()); + + /* lose our controlling terminal + */ + if (-1 != (td = open("/dev/tty", O_RDWR, 0600))) { + (void)ioctl(td, TIOCNOTTY, (char *)0); + close(td); + } +#endif +} + + +static char *apcLong[] = { + "a type set the default access type", + "C config give a new config file to the server process", + "d become a daemon, output to /dev/null", + "h output this message", + "n do not output summary stream to stdout", + "v be verbose on startup", + "V output version info", + (char *)0 +}; + +/* output a long message to the user (ksb) + */ +static void +Usage(fp, ppc) +FILE *fp; +char **ppc; +{ + for (/* passed */; (char *)0 != *ppc; ++ppc) + (void)fprintf(fp, "%s\n", *ppc); +} + +/* show the user our version info (ksb) + */ +static void +Version() +{ + auto char acA1[16], acA2[16]; + + printf("%s: %s\n", progname, GNAC_VERSION); + printf("%s: default access type `%c\'\n", progname, chDefAcc); + printf("%s: default escape sequence `%s%s\'\n", progname, FmtCtl(DEFATTN, acA1), FmtCtl(DEFESC, acA2)); + printf("%s: configuration in `%s\'\n", progname, pcConfig); + printf("%s: password in `%s\'\n", progname, PASSWD_FILE); + printf("%s: limited to %d group%s with %d member%s\n", progname, MAXGRP, MAXGRP == 1 ? "" : "s", MAXMEMB, MAXMEMB == 1 ? "" : "s"); +#if defined(SERVICE) + { + struct servent *pSE; + if ((struct servent *)0 == (pSE = getservbyname(acService, "tcp"))) { + fprintf(stderr, "%s: getservbyname: %s: %s\n", progname, acService, strerror(errno)); + return; + } + printf("%s: service name `%s\'", progname, pSE->s_name); + if (0 != strcmp(pSE->s_name, acService)) { + printf(" (which we call `%s\')", acService); + } + printf(" on port %d\n", ntohs((u_short)pSE->s_port)); + } +#else +#if defined(PORT) + printf("%s: on port %d\n", progname, PORT); +#else + printf("%s: no service or port compiled in\n", progname); + exit(1); +#endif +#endif +} + +/* find out where/who we are (ksb) + * parse optons + * read in the config file, open the log file + * spawn the kids to drive the console groups + * become the master server + * shutdown with grace + * exit happy + */ +int +main(argc, argv) +int argc; +char **argv; +{ + register int i, j; + register FILE *fpConfig; + auto struct hostent *hpMe; + static char acOpts[] = "a:C:dhnsVv", + u_terse[] = " [-dhnsvV] [-a type] [-C config]"; + extern int optopt; + extern char *optarg; + auto REMOTE + *pRCUniq; /* list of uniq console servers */ + + if ((char *)0 == (progname = strrchr(argv[0], '/'))) { + progname = argv[0]; + } else { + ++progname; + } + + (void)setpwent(); +#if USE_SETLINEBUF + setlinebuf(stderr); +#endif +#if USE_SETVBUF + setvbuf(stderr, NULL, _IOLBF, BUFSIZ); +#endif + + (void)gethostname(acMyHost, sizeof(acMyHost)); + if ((struct hostent *)0 == (hpMe = gethostbyname(acMyHost))) { + fprintf(stderr, "%s: gethostbyname: %s\n", progname, hstrerror(h_errno)); + exit(1); + } + if (sizeof(acMyAddr) != hpMe->h_length || AF_INET != hpMe->h_addrtype) { + fprintf(stderr, "%s: wrong address size (%d != %d) or adress family (%d != %d)\n", progname, sizeof(acMyAddr), hpMe->h_length, AF_INET, hpMe->h_addrtype); + exit(1); + } +#if USE_STRINGS + (void)bcopy(hpMe->h_addr, &acMyAddr[0], hpMe->h_length); +#else + (void)memcpy(&acMyAddr[0], hpMe->h_addr, hpMe->h_length); +#endif + + while (EOF != (i = getopt(argc, argv, acOpts))) { + switch (i) { + case 'a': + chDefAcc = '\000' == *optarg ? 'r' : *optarg; + if (isupper(chDefAcc)) { + chDefAcc = tolower(chDefAcc); + } + switch (chDefAcc) { + case 'r': + case 'a': + case 't': + break; + default: + fprintf(stderr, "%s: unknown access type `%s\'\n", progname, optarg); + exit(3); + } + break; + case 'C': + pcConfig = optarg; + break; + case 'd': + fDaemon = 1; + break; + case 'h': + fprintf(stderr, "%s: usage%s\n", progname, u_terse); + Usage(stdout, apcLong); + exit(0); + case 'n': + fAll = 0; + break; + case 's': + fSoftcar ^= 1; + break; + case 'V': + Version(); + exit(0); + case 'v': + fVerbose = 1; + break; + case '\?': + fprintf(stderr, "%s: usage%s\n", progname, u_terse); + exit(1); + default: + fprintf(stderr, "%s: option %c needs a parameter\n", progname, optopt); + exit(1); + } + } + +/* Why force root??? Cause of getsp*() calls... */ + if (0 != geteuid()) { + fprintf(stderr, "%s: must be the superuser\n", progname); + exit(1); + } + + /* read the config file + */ + if ((FILE *)0 == (fpConfig = fopen(pcConfig, "r"))) { + fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcConfig, strerror(errno)); + exit(1); + } + ReadCfg(pcConfig, fpConfig); + +#if USE_FLOCK + /* we lock the configuration file so that two identical + * conservers will not be running together (but two with + * different configurations can run on the same host). + */ + if (-1 == flock(fileno(fpConfig), LOCK_NB|LOCK_EX)) { + fprintf(stderr, "%s: %s is locked, won\'t run more than one conserver?\n", progname, pcConfig); + exit(3); + } +#endif + + /* if no one can use us we need to come up with a default + */ + if (0 == iAccess) { + SetDefAccess(hpMe); + } + +#if USE_SETLINEBUF + setlinebuf(stdout); +#endif +#if USE_SETVBUF + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); +#endif + + (void)fflush(stdout); + (void)fflush(stderr); + if (fDaemon) { + daemonize(); + } + /* spawn all the children, so fix kids has an initial pid + */ + for (i = 0; i < MAXGRP; ++i) { + if (0 == aGroups[i].imembers) + continue; + if (aGroups[i].imembers) { + Spawn(& aGroups[i]); + } + if (fVerbose) { + printf("%s: group %d on port %d\n", progname, i, ntohs((u_short)aGroups[i].port)); + } + for (j = 0; j < aGroups[i].imembers; ++j) { + if (-1 != aGroups[i].pCElist[j].fdtty) + (void)close(aGroups[i].pCElist[j].fdtty); + } + } + + if (fVerbose) { + for (i = 0; i < iAccess; ++i) { + printf("%s: access type '%c' for \"%s\"\n", progname, pACList[i].ctrust, pACList[i].pcwho); + } + } + + pRCUniq = FindUniq(pRCList); + /* output unique console server peers? + */ + if (fVerbose) { + register REMOTE *pRC; + for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { + printf("%s: peer server on `%s'\n", progname, pRC->rhost); + } + } + + (void)fflush(stdout); + (void)fflush(stderr); +/* + if (fDaemon) { + daemonize(); + } +*/ + Master(pRCUniq); + + /* stop putting kids back, and shoot them + */ + (void)signal(SIGCHLD, SIG_DFL); + for (i = 0; i < MAXGRP; ++i) { + if (0 == aGroups[i].imembers) + continue; + if (-1 == kill(aGroups[i].pid, SIGTERM)) { + fprintf(stderr, "%s: kill: %s\n", progname, strerror(errno)); + } + } + + (void)endpwent(); + (void)fclose(fpConfig); + exit(0); +} diff --git a/conserver/main.h b/conserver/main.h new file mode 100644 index 0000000..56e7490 --- /dev/null +++ b/conserver/main.h @@ -0,0 +1,43 @@ +/* + * $Id: main.h,v 5.8 1998-11-17 18:42:27-08 bryan Exp $ + * + * 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. + */ + +/* program options and stuff + */ +extern char rcsid[]; +extern char *progname; +extern int fAll, fVerbose, fSoftcar, fInteractive; +extern char chDefAcc; +extern char *pcConfig; +extern struct sockaddr_in in_port; +extern char acMyHost[]; +extern int domainHack; + +#if defined(SERVICE) +extern char acService[]; +#endif + diff --git a/conserver/master.c b/conserver/master.c new file mode 100644 index 0000000..3d996f5 --- /dev/null +++ b/conserver/master.c @@ -0,0 +1,453 @@ +/* + * $Id: master.c,v 5.19 1998-11-17 23:14:51-08 bryan Exp $ + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "consent.h" +#include "client.h" +#include "group.h" +#include "access.h" +#include "master.h" +#include "readcfg.h" +#include "version.h" +#include "main.h" + +#if USE_STRINGS +#include +#else +#include +#endif + +#if USE_SYS_TIME_H +#include +#else +#include +#endif +#include + +extern char *crypt(); +extern time_t time(); + + +/* check all the kids and respawn as needed. (fine) + * Called when master process receives SIGCHLD + */ +static SIGRETS +FixKids(arg) + int arg; +{ + register int i, pid; + auto long tyme; + auto WAIT_T UWbuf; + +#if HAVE_WAIT3 + while (-1 != (pid = wait3(& UWbuf, WNOHANG, (struct rusage *)0))) { +#else + while (-1 != (pid = wait(& UWbuf))) { +#endif + if (0 == pid) { + break; + } + /* stopped child is just continuted + */ + if (WIFSTOPPED(UWbuf) && 0 == kill(pid, SIGCONT)) { + continue; + } + + for (i = 0; i < MAXGRP; ++i) { + if (0 == aGroups[i].imembers) + continue; + if (pid != aGroups[i].pid) + continue; + + /* this kid kid is dead, start another + */ + Spawn(& aGroups[i]); + tyme = time((long *)0); + printf("%s: %s: exit(%d), restarted %s", progname, aGroups[i].pCElist[0].server, WEXITSTATUS(UWbuf), ctime(&tyme)); + } + } +} + +static int fSawQuit; + +/* kill all the kids and exit. + * Called when master process receives SIGTERM + */ +static SIGRETS +QuitIt(arg) + int arg; +{ + ++fSawQuit; +} + + +/* this routine is used by the master console server process (ksb) + */ +void +Master(pRCUniq) +REMOTE + *pRCUniq; /* list of uniq console servers */ +{ + register char *pcArgs; + register int i, j, cfd; + register REMOTE *pRC, *pRCFound; + register int nr, prnum, found, msfd; + register struct hostent *hpPeer; + auto char cType; + auto int so; + auto fd_set rmask, rmaster; + auto char acIn[1024], acOut[BUFSIZ]; + auto struct sockaddr_in master_port, response_port; + int true = 1; + + /* set up signal handler */ + (void)signal(SIGCHLD, FixKids); + (void)signal(SIGTERM, QuitIt); + + /* set up port for master to listen on + */ +#if USE_STRINGS + (void)bzero((char *)&master_port, sizeof(master_port)); +#else + (void)memset((void *)&master_port, 0, sizeof(master_port)); +#endif + master_port.sin_family = AF_INET; + *(u_long *)&master_port.sin_addr = INADDR_ANY; +#if defined(SERVICE) + { + struct servent *pSE; + if ((struct servent *)0 == (pSE = getservbyname(acService, "tcp"))) { + fprintf(stderr, "%s: getservbyname: %s: %s\n", progname, acService, strerror(errno)); + return; + } + master_port.sin_port = pSE->s_port; + } +#else +#if defined(PORT) + master_port.sin_port = htons((u_short)PORT); +#else + fprintf(stderr, "%s: no port or service compiled in?\n", progname); +#endif +#endif + + if ((msfd=socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "%s: socket: %s\n", progname, strerror(errno)); + return; + } +#if HAVE_SETSOCKOPT + if (setsockopt(msfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, sizeof(true))<0) { + fprintf(stderr, "%s: setsockopt: %s\n", progname, strerror(errno)); + return; + } +#endif + if (bind(msfd, (struct sockaddr *)&master_port, sizeof(master_port))<0) { + fprintf(stderr, "%s: bind: %s\n", progname, strerror(errno)); + return; + } + if (listen(msfd, SOMAXCONN) < 0) { + fprintf(stderr, "%s: listen: %s\n", progname, strerror(errno)); + } + + FD_ZERO(&rmaster); + FD_SET(msfd, &rmaster); + for (fSawQuit = 0; !fSawQuit; /* can't close here :-( */) { + rmask = rmaster; + + if (-1 == select(msfd+1, &rmask, (fd_set *)0, (fd_set *)0, (struct timeval *)0)) { + fprintf(stderr, "%s: select: %s\n", progname, strerror(errno)); + continue; + } + if (!FD_ISSET(msfd, &rmask)) { + continue; + } + so = sizeof(response_port); + cfd = accept(msfd, (struct sockaddr *)&response_port, &so); + if (cfd < 0) { + fprintf(stderr, "%s: accept: %s\n", progname, strerror(errno)); + continue; + } + + + so = sizeof(in_port); + if (-1 == getpeername(cfd, (struct sockaddr *)&in_port, &so)) { + CSTROUT(cfd, "getpeername failed\r\n"); + (void)close(cfd); + continue; + } + so = sizeof(in_port.sin_addr); + if ((struct hostent *)0 == (hpPeer = gethostbyaddr((char *)&in_port.sin_addr, so, AF_INET))) { + CSTROUT(cfd, "unknown peer name\r\n"); + (void)close(cfd); + continue; + } + if ('r' == (cType = AccType(hpPeer))) { + CSTROUT(cfd, "access from your host refused\r\n"); + (void)close(cfd); + continue; + } + +#if TEST_FORK + /* we should fork here, or timeout + */ + switch(fork()) { + default: + (void)close(cfd); + continue; + case -1: + CSTROUT(cfd, "fork failed, try again\r\n"); + (void)close(cfd); + continue; + case 0: + break; + } +#endif + /* handle the connection + * (port lookup, who, users, or quit) + */ + CSTROUT(cfd, "ok\r\n"); + for (i = 0; i < sizeof(acIn); /* i+=nr */) { + if (0 >= (nr = read(cfd, &acIn[i], sizeof(acIn)-1-i))) { + i = 0; + break; + } + i += nr; + if ('\n' == acIn[i-1]) { + acIn[i] = '\000'; + --i; + break; + } + } + if (i > 0 && '\n' == acIn[i-1]) { + acIn[--i] = '\000'; + } + if (i > 0 && '\r' == acIn[i-1]) { + acIn[--i] = '\000'; + } + if (0 == i) { + fprintf(stderr, "%s: lost connection\n", progname); + (void)close(cfd); +#if TEST_FORK + exit(1); +#else + continue; +#endif + } + if ((char *)0 != (pcArgs = strchr(acIn, ':'))) { + *pcArgs++ = '\000'; + } else if ((char *)0 != (pcArgs = strchr(acIn, ' '))) { + *pcArgs++ = '\000'; + } + if (0 == strcmp(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 + }; + register char **ppc; + for (ppc = apcHelp; (char *)0 != *ppc; ++ppc) { + (void)write(cfd, *ppc, strlen(*ppc)); + } + (void)close(cfd); +#if TEST_FORK + exit(0); +#else + continue; +#endif + } + if (0 == strcmp(acIn, "quit")) { + register struct passwd *pwd; + + if ('t' == cType) { + CSTROUT(cfd, "trusted -- terminated\r\n"); +#if TEST_FORK + kill(getppid(), SIGTERM); +#else + fSawQuit = 1; +#endif + } else if ((char *)0 == pcArgs) { + CSTROUT(cfd, "must be trusted to terminate\r\n"); + } else if ((struct passwd *)0 == (pwd = getpwuid(0))) { + CSTROUT(cfd, "no root passwd?\r\n"); + } else if (0 == CheckPass(pwd, (char *)0, pcArgs)) { + CSTROUT(cfd, "Sorry.\r\n"); + } else { + CSTROUT(cfd, "ok -- terminated\r\n"); +#if TEST_FORK + kill(getppid(), SIGTERM); +#else + fSawQuit = 1; +#endif + } + (void)close(cfd); +#if TEST_FORK + exit(0); +#else + continue; +#endif + } + if (0 == strcmp(acIn, "pid")) { +#if TEST_FORK + sprintf(acOut, "%d\r\n", getppid()); + (void)write(cfd, acOut, strlen(acOut)); + exit(0); +#else + sprintf(acOut, "%d\r\n", getpid()); + (void)write(cfd, acOut, strlen(acOut)); + continue; +#endif + } + if (0 == strcmp(acIn, "groups")) { + register int iSep = 1; + + for (i = 0; i < MAXGRP; ++i) { + if (0 == aGroups[i].imembers) + continue; + sprintf(acOut, ":%d"+iSep, ntohs((u_short)aGroups[i].port)); + (void)write(cfd, acOut, strlen(acOut)); + iSep = 0; + } + CSTROUT(cfd, "\r\n"); + (void)close(cfd); +#if TEST_FORK + exit(0); +#else + continue; +#endif + } + if (0 == strcmp(acIn, "master")) { + register int iSep = 1; + + if (0 != iLocal) { + sprintf(acOut, "@%s", acMyHost); + (void)write(cfd, acOut, strlen(acOut)); + iSep = 0; + } + for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { + sprintf(acOut, ":@%s"+iSep, pRC->rhost); + (void)write(cfd, acOut, strlen(acOut)); + iSep = 0; + } + CSTROUT(cfd, "\r\n"); + (void)close(cfd); +#if TEST_FORK + exit(0); +#else + continue; +#endif + } + if (0 == strcmp(acIn, "version")) { + sprintf(acOut, "version `%s\'\r\n", GNAC_VERSION); + (void)write(cfd, acOut, strlen(acOut)); +#if TEST_FORK + exit(0); +#else + continue; +#endif + } + if (0 != strcmp(acIn, "call")) { + CSTROUT(cfd, "unknown command\r\n"); + (void)close(cfd); +#if TEST_FORK + exit(0); +#else + continue; +#endif + } + + /* look up the machine to call + */ + found = 0; + pRCFound = (REMOTE *)0; + /* look for a local machine */ + for (i = 0; i < MAXGRP; ++i) { + if (0 == aGroups[i].imembers) + continue; + for (j = 0; j < aGroups[i].imembers; ++j) { + if (0 != strcmp(pcArgs, aGroups[i].pCElist[j].server)) { + continue; + } + prnum = ntohs((u_short)aGroups[i].port); + ++found; + } + } + if ( found == 0 ) { /* Then look for substring matches */ + for (i = 0; i < MAXGRP; ++i) { + if (0 == aGroups[i].imembers) + continue; + for (j = 0; j < aGroups[i].imembers; ++j) { + if (0 != strncmp(pcArgs, aGroups[i].pCElist[j].server, strlen(pcArgs))) { + continue; + } + prnum = ntohs((u_short)aGroups[i].port); + ++found; + } + } + } + /* look for a remote server */ + for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext) { + if (0 != strncmp(pcArgs, pRC->rserver, strlen(pcArgs))) { + continue; + } + ++found; + pRCFound = pRC; + } + switch (found) { + case 0: + sprintf(acOut, "server %s not found\r\n", pcArgs); + break; + case 1: + if ((REMOTE *)0 != pRCFound) { + sprintf(acOut, "@%s\r\n", pRCFound->rhost, pcArgs); + } else { + sprintf(acOut, "%d\r\n", prnum); + } + break; + default: + sprintf(acOut, "ambigous server abbreviation, %s\r\n", pcArgs); + break; + } + (void)write(cfd, acOut, strlen(acOut)); + (void)close(cfd); +#if TEST_FORK + exit(0); +#endif + } +} diff --git a/conserver/master.h b/conserver/master.h new file mode 100644 index 0000000..0a74836 --- /dev/null +++ b/conserver/master.h @@ -0,0 +1,32 @@ +/* + * $Id: master.h,v 5.6 1993-02-09 04:01:31-08 ldv Exp $ + * + * 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. + */ + +/* + * stuff the master process needs + */ +extern void Master(); diff --git a/conserver/readcfg.c b/conserver/readcfg.c new file mode 100644 index 0000000..5ec1436 --- /dev/null +++ b/conserver/readcfg.c @@ -0,0 +1,384 @@ +/* + * $Id: readcfg.c,v 5.21 1998-12-14 11:20:15-08 bryan Exp $ + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "consent.h" +#include "client.h" +#include "group.h" +#include "access.h" +#include "readcfg.h" +#include "master.h" +#include "main.h" + +#if USE_STRINGS +#include +#else +#include +#endif + + +GRPENT + aGroups[MAXGRP]; /* even spread is OK */ +CONSENT + aConsoles[MAXGRP*MAXMEMB]; /* gross over allocation */ +REMOTE + *pRCList; /* list of remote consoles we know about */ +int + iLocal; /* number of local consoles */ + +ACCESS + *pACList; /* `who do you love' (or trust) */ +int + iAccess; /* how many access restrictions we have */ + +/* read in the configuration file, fill in all the structs we use (ksb) + * to manage the consoles + */ +void +ReadCfg(pcFile, fp) +char *pcFile; +register FILE *fp; +{ + register GRPENT *pGE; + register int iG, minG; + auto int iLine; + auto char acIn[BUFSIZ]; + register GRPENT *pGEAll; + register CONSENT *pCE; + register REMOTE **ppRC; + char LogDirectory[MAXLOGLEN]; + long tyme; + + tyme = time((long *)0); + LogDirectory[0] = '\000'; + pGEAll = aGroups; /* fill in these structs */ + pCE = aConsoles; + ppRC = & pRCList; + iLocal = 0; + + iG = minG = 0; + iLine = 0; + while (fgets(acIn, sizeof(acIn)-1, fp) != NULL) { + register char *pcLine, *pcMode, *pcLog, *pcRem, *pcStart, *pcMark; + + ++iLine; + for (pcRem = acIn+strlen(acIn)-1; pcRem >= acIn; --pcRem) { + if (!isspace(*pcRem)) + break; + *pcRem = '\000'; + if (pcRem == acIn) + break; + } + if ('#' == acIn[0] || '\000' == acIn[0]) { + continue; + } + if ('%' == acIn[0] && '%' == acIn[1] && '\000' == acIn[2]) { + break; + } + if ( (char *)0 == strchr(acIn, ':') && + (char *)0 != (pcLine = strchr(acIn, '=')) ) { + *pcLine = '\000'; + if ( 0 == strcmp(acIn, "LOGDIR") ) { + (void)strcpy(LogDirectory, ++pcLine); + } else if ( 0 == strcmp(acIn, "DOMAINHACK") ) { + domainHack = 1; + } else { + *pcLine = '='; + fprintf(stderr, "%s: %s(%d) bad variable line `%s'\n", progname, pcFile, iLine, acIn); + } + continue; + } + if ( (char *)0 == (pcLine = strchr(acIn, ':')) || + (char *)0 == (pcMode = strchr(pcLine+1, ':')) || + (char *)0 == (pcLog = strchr(pcMode+1, ':'))) { + fprintf(stderr, "%s: %s(%d) bad config line `%s'\n", progname, pcFile, iLine, acIn); + continue; + } + *pcLine++ = '\000'; + *pcMode++ = '\000'; + *pcLog++ = '\000'; + + if ((char *)0 != (pcMark = strchr(pcLog, ':'))) { + *pcMark++ = '\000'; + /* Skip null intervals */ + if ( pcMark[0] == '\000' ) pcMark = (char *)0; + } + + /* 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) + */ + if ((char *)0 != (pcRem = strchr(pcLine, '@')) && + ((*pcRem++ = '\000'), 0 != strcmp(acMyHost, pcRem))) { + register REMOTE *pRCTemp; + pRCTemp = (REMOTE *)calloc(1, sizeof(REMOTE)); + if ((REMOTE *)0 == pRCTemp) { + CSTROUT(2, "out of memory!\n"); + exit(32); + } + (void)strcpy(pRCTemp->rhost, pcRem); + (void)strcpy(pRCTemp->rserver, acIn); + *ppRC = pRCTemp; + ppRC = & pRCTemp->pRCnext; + if (fVerbose) { + printf("%s: %s remote on %s\n", progname, acIn, pcRem); + } + continue; + } + + /* take the same group as the last line, by default + */ + if (MAXMEMB == pGEAll[iG].imembers) { + ++iG; + } + if (iG < minG || iG >= MAXGRP) { + fprintf(stderr, "%s: %s(%d) group number out of bounds %d <= %d < %d\n", progname, pcFile, iLine, minG, iG, MAXGRP); + exit(1); + } + minG = iG; + pGE = pGEAll+iG; + if (0 == pGE->imembers++) { + pGE->pCElist = pCE; + } + if (pGE->imembers > MAXMEMB) { + fprintf(stderr, "%s: %s(%d) group %d has more than %d members -- but we'll give it a spin\n", progname, pcFile, iLine, iG, MAXMEMB); + } + + /* fill in the console entry + */ + if (sizeof(aConsoles)/sizeof(CONSENT) == iLocal) { + fprintf(stderr, "%s: %s(%d) %d is too many consoles for hard coded tables, adjust MAXGRP or MAXMEMB\n", progname, pcFile, iLine, iLocal); + exit(1); + } + (void)strcpy(pCE->server, acIn); + +/* + * 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. + */ + *(pCE->lfile) = '\000'; + pcStart = pcLog; + while ((char *)0 != (pcRem = strchr(pcStart, '&'))) { + *pcRem = '\000'; + (void)strcat(pCE->lfile, pcStart); + (void)strcat(pCE->lfile, acIn); + pcStart = pcRem + 1; + } + (void)strcat(pCE->lfile, pcStart); + if ( LogDirectory[0] && (pCE->lfile)[0] != '/' ) { + char lfile[MAXLOGLEN]; + strcpy( lfile, pCE->lfile ); + strcpy( pCE->lfile, LogDirectory ); + strcat( pCE->lfile, "/" ); + strcat( pCE->lfile, lfile ); + } + + if ( pcMark ) { + int factor; + char *p; + p = pcMark + strlen(pcMark) - 1; + if ( *p == 'm' ) { + factor = 60; + } else if ( *p == 'h' ) { + factor = 60 * 60; + } else if ( *p == 'd' ) { + factor = 60 * 60 * 24; + } else { + fprintf(stderr, "%s: %s(%d) bad mark specification `%s'\n", progname, pcFile, iLine, pcMark); + pcMark = 0; + factor = 0; + } + if ( factor ) { + *p = '\000'; + pCE->mark = atoi(pcMark) * factor; + pCE->nextMark = tyme + pCE->mark; + if ( pCE->mark < 0 ) { + fprintf(stderr, "%s: %s(%d) negative mark specification `%s'\n", progname, pcFile, iLine, pcMark); + pcMark = 0; + } + } + } + if ( !pcMark ) { + pCE->nextMark = pCE->mark = 0; + } + +#if DO_VIRTUAL + if (pcLine[0] == '!') + { + pCE->isNetworkConsole = 1; + strcpy(pCE->networkConsoleHost, pcLine + 1); + pCE->networkConsolePort = atoi(pcMode); + + if (fVerbose) { + printf("%s: %d: %s is network on %s/%d logged to %s\n", + progname, iG, acIn, pCE->networkConsoleHost, + pCE->networkConsolePort, pCE->lfile); + } + pCE->fvirtual = 0; + sprintf( pCE->dfile, "%s/%d", pCE->networkConsoleHost, pCE->networkConsolePort ); + pCE->pbaud = FindBaud("Netwk"); + pCE->pparity = FindParity(" "); + } + else if ('|' == pcLine[0]) { + pCE->isNetworkConsole = 0; + pCE->fvirtual = 1; + if ((char *)0 == (pCE->pccmd = malloc((strlen(pcLine)|7)+1))) { + OutOfMem(); + } + (void)strcpy(pCE->pccmd, pcLine+1); + (void)strcpy(pCE->dfile, "/dev/null"); + } else { + pCE->isNetworkConsole = 0; + pCE->fvirtual = 0; + (void)strcpy(pCE->dfile, pcLine); + } + pCE->ipid = -1; +#else + if ('|' == pcLine[0]) { + fprintf(stderr, "%s: %s(%d) this server doesn't provide any virtual console support\n", progname, pcFile, iLine); + exit(9); + } + (void)strcpy(pCE->dfile, pcLine); +#endif + + if (!pCE->isNetworkConsole) + { + /* find user baud and parity + * default to first table entry for baud and parity + */ + pCE->pbaud = FindBaud(pcMode); + pCE->pparity = FindParity(pcMode); + if (fVerbose) { +#if DO_VIRTUAL + if (pCE->fvirtual) + printf("%s: %d: %s with command `%s' logged to %s\n", progname, iG, acIn, pCE->pccmd, pCE->lfile); + else +#endif + printf("%s: %d: %s is on %s (%s%c) logged to %s\n", progname, iG, acIn, pCE->dfile, pCE->pbaud->acrate, pCE->pparity->ckey, pCE->lfile); + } + } + ++pCE, ++iLocal; + } + *ppRC = (REMOTE *)0; + + /* make a vector of access restructions + */ + iG = iAccess = 0; + pACList = (ACCESS *)0; + while (fgets(acIn, sizeof(acIn)-1, fp) != NULL) { + register char *pcRem, *pcMach, *pcNext, *pcMem; + auto char cType; + auto int iLen; + + ++iLine; + for (pcRem = acIn+strlen(acIn); pcRem >= acIn; --pcRem) { + if (!isspace(*pcRem)) + break; + *pcRem = '\000'; + if (pcRem == acIn) + break; + } + if ('#' == acIn[0] || '\000' == acIn[0]) { + continue; + } + if ('%' == acIn[0] && '%' == acIn[1] && '\000' == acIn[2]) { + break; + } + if ((char *)0 == (pcNext = strchr(acIn, ':'))) { + fprintf(stderr, "%s: %s(%d) missing colon?\n", progname, pcFile, iLine); + exit(3); + } + do { + *pcNext++ = '\000'; + } while (isspace(*pcNext)); + switch (acIn[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: + fprintf(stderr, "%s: %s(%d) unknown access key `%s\'\n", progname, pcFile, iLine, acIn); + exit(3); + } + while ('\000' != *(pcMach = pcNext)) { + while (!isspace(*pcNext)) { + ++pcNext; + } + while ('\000' != *pcNext && isspace(*pcNext)) { + *pcNext++ = '\000'; + } + if (iAccess < iG) { + /* still have room */; + } else if (0 != iG) { + iG += 8; + pACList = (ACCESS *)realloc((char *)pACList, iG * sizeof(ACCESS)); + } else { + iG = MAXGRP; + pACList = (ACCESS *)malloc(iG * sizeof(ACCESS)); + } + if ((ACCESS *)0 == pACList) { + OutOfMem(); + } + /* use loopback interface for local connections + if (0 == strcmp(pcMach, acMyHost)) { + pcMach = "127.0.0.1"; + } + */ + iLen = strlen(pcMach); + if ((char *)0 == (pcMem = malloc(iLen+1))) { + OutOfMem(); + } + pACList[iAccess].ctrust = cType; + pACList[iAccess].ilen = iLen; + pACList[iAccess].pcwho = strcpy(pcMem, pcMach); + ++iAccess; + } + } +} diff --git a/conserver/readcfg.h b/conserver/readcfg.h new file mode 100644 index 0000000..96ff0c9 --- /dev/null +++ b/conserver/readcfg.h @@ -0,0 +1,47 @@ +/* + * $Id: readcfg.h,v 5.6 1993-02-09 03:59:25-08 ldv Exp $ + * + * 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. + */ + +/* we read in which hosts to trust and which ones we proxy for + * from a file, into these structures + */ + +extern GRPENT + aGroups[MAXGRP]; /* group info */ +extern CONSENT + aConsoles[MAXGRP*MAXMEMB]; /* console list */ +extern REMOTE + *pRCList; /* list of remote consoles we know about */ +extern ACCESS + *pACList; /* `who do you love' (or trust) */ + +extern int + iAccess; /* how many access restrictions we have */ +extern int + iLocal; /* how many local consoles we have */ + +extern void ReadCfg(); diff --git a/conserver/stamper.sh b/conserver/stamper.sh new file mode 100644 index 0000000..6f15c8d --- /dev/null +++ b/conserver/stamper.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# $Id: stamper.sh,v 4.1 91/06/19 14:40:46 ksb Exp $ +# +# The outputs a time stamp once an hour (on the hour, we hope). +# We take a list of logfiles to stamp +# +PROGNAME=`basename $0 .sh` +if [ "$#" -eq 0 ] +then + echo "$PROGNAME: usage files" 1>&2 + exit 1 +fi + +# sleep until the top of the hour +# output a mark on each log file +# sleep for nearly an hour +while true +do + ( + IFS="$IFS:" + + # _ Wed Jun 19 14:31:02 EST 1991 + # $1 $2 $3 $4 $5 $6 $7 $8 $9 + set _ `date` + + #sleep `expr 3600 - \( $6 \* 60 + $7 \)` + ) + + mark="[-- MARK -- `date`]" + for file + do + if [ _"-" = _"$file" ] + then + echo "$mark" + else + echo "$mark" >>$file + fi + done + + sleep 3530 +done + +# NOTREACHED +exit 0 diff --git a/conserver/version.h b/conserver/version.h new file mode 100644 index 0000000..a0ef628 --- /dev/null +++ b/conserver/version.h @@ -0,0 +1 @@ +#define GNAC_VERSION "GNAC version 6.05" diff --git a/console/INSTALL b/console/INSTALL new file mode 100644 index 0000000..0138f09 --- /dev/null +++ b/console/INSTALL @@ -0,0 +1,35 @@ +# $Id: INSTALL,v 4.1 91/06/19 15:27:49 ksb Exp $ +# + +Prep: + + Did you do the prep work in ../conserver yet? If not please start there. + + +Compiling: + + Try a + make + in this directory. If cons.h is correct this should just compile. + + +First test: + + Run a version command: + ./console -V + and see something like: + console: $Id: INSTALL,v 4.1 91/06/19 15:27:49 ksb Exp $ + console: initial master server `staff.cc.purdue.edu' + console: default escape sequence `^Ec' + console: loopback address for mentor.cc.purdue.edu is 127.0.0.1 + + + Finish the INSTALL in conserver now. + + +Connect to the conserver on your dumb port, + + Try all the commands. Especially ^Ecz and ^Ecd/^Eco. + + Try two connections to the same console, note the cool way you can force + the other guy off (^Ecf). diff --git a/console/Makefile b/console/Makefile new file mode 100644 index 0000000..68d6a90 --- /dev/null +++ b/console/Makefile @@ -0,0 +1,81 @@ +# $Id: Make.host,v 5.10 94/07/26 11:06:26 ksb Exp $ +# +# Makefile for console client progran +# + +# edit the ETC directory below to change where the console client +# is installed. +PROG= console +ETC= ${DESTDIR}/usr/local/etc +DOC= ${DESTDIR}/usr/local/man + +I=/usr/include +S=/usr/include/sys +L=/usr/local/include +C=../conserver +P= + +INCLUDE= -I$C +DEBUG=-O +CDEFS= -DSUN5 +CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE} + +HDR= +ONEC= console.c +MAN= console.man +OTHER= README +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${ONEC} + +all: ${PROG} + +${PROG}: + ${CC} -o $@ ${CFLAGS} ${ONEC} -lsocket -lnsl + +clean: FRC + rm -f Makefile.bak ${PROG} a.out *.o core errs lint.out tags + +deinstall: ${MAN} ${DOC} FRC + install -R ${ETC}/${PROG} + mkcat -r${DOC} -D ${MAN} + +depend: ${HDR} ${ONEC} FRC + maketd -b ${CDEFS} ${INCLUDE} ${ONEC} + +dirs: ${ETC} + +distrib: FRC + distrib -c ${ETC}/${PROG} + +install: all dirs FRC + install -cs ${PROG} ${ETC}/${PROG} + +lint: ${HDR} ${ONEC} FRC + lint -h ${CDEFS} ${INCLUDE} ${ONEC} + +mkcat: ${MAN} ${DOC} FRC + mkcat -r${DOC} ${MAN} + +print: source FRC + lpr -J"${PROG} source" ${SOURCE} + +source: ${SOURCE} + +spotless: clean + rcsclean ${SOURCE} + +tags: ${HDR} ${ONEC} + ctags -t ${HDR} ${ONEC} + +/ ${ETC}: + install -dr $@ + +${SOURCE}: + co -q $@ + +FRC: + +# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT + +console: $C/cons.h console.c + +# *** Do not add anything here - It will go away. *** diff --git a/console/README b/console/README new file mode 100644 index 0000000..c99e121 --- /dev/null +++ b/console/README @@ -0,0 +1,67 @@ +# $Id: README,v 4.2 92/07/27 08:47:14 ksb Exp $ + +BUGS: + This program depends on a header file in ../conserver/cons.h, + which is dones't know how to make. + +What does it do? + + The console switch (conserver) uses some tty ports on a `switch machine' to + read the output of many host machines. Admins can use a client program + (console) to connect to any console under control of the `switch'. Thus from + my terminal here on the second floor I can control the console for each of + the machines in the machine room 3 floors below me! + + The `switch' host is monitored by an operator who sees all the error output + from all the consoles (in a xterm here at PUCC). This operator can call up a + console on any machine in a flash and respond to problems. He is aware of + problems without having to poll many CRTs stacked out in the machine room -- + he and the tape drives can be in a quiet place. + + +What platforms? + + It runs under 4.2/4.3bsd, IBM's AIX6000, SunOS 4.X, and HPUX. + Only the client runs under HPUX at this release. It depends on + select(2) and sockets. + + +What do I need to evaluate it? + + I believe a modem could be used in a pinch as a `host', anything that you can + trick into producing tty I/O. Even a dumb tty, but then you must do the + echo. Another port on the same machine was used for testing at one point... + and an EPROM programmer might even work. + + +Who would be interested in this kind of thing? + + Anyone with more than one machine with a glass tty would love it, it also + gets rid of the need for paper consoles. + + +Is this software restricted in distribution? + + Tom has an Ohio State copyright on the stuff, I'm sure that there will be no + problem with distribution. {He ripped the Purdue ECN copyright off the code + he got, I didn't change his.} Tom has not replied to any of my email in ~3 + months.... + + +Why this version rather than any other? + + The PUCC version supports many more features (multiple `switch' machines for + when you run out of ports; job control; down'd consoles, etc) than either the + Ohio State or Purdue ECN versions. + + +How much trouble is it to port? + + The code is ~2000 lines for the server and ~1150 for the client. Not too + hard to read in ~3 hours. It should work with a little push on any BSD type + UNIX. + + +-- +"When you find me here, at the end of my rope!" +kayessbee, Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb diff --git a/console/console.8l b/console/console.8l new file mode 100644 index 0000000..fdf9615 --- /dev/null +++ b/console/console.8l @@ -0,0 +1,185 @@ +.\" $Id: console.8l,v 5.0 92/01/13 14:44:36 ksb Exp $ +.TH CONSOLE 8L "Local" +.SH NAME +console \- console server client program +.SH SYNOPSIS +\fBconsole\fP [\-\fBrv\fP] [\-\fBAFSafs\fP] [\-\fBe\fP \fIesc\fP] [\-\fBM\fP \fIserver\fP] \fIhost\fP +.br +\fBconsole\fP [\-\fBdDqQ\fP] [\-\fBv\fP] [\-\fBM\fP \fIserver\fP] \fIhost\fP +.br +\fBconsole\fP [\-\fBv\fP] [\-\fBhuVwx\fP] +.SH DESCRIPTION +.B Console +is used to manipulate console terminals remotely or poll running +\fIconserver\fP(8L) daemons for status information. +.PP +.B Console +queries the user for the root passwd before +granting interactive access to a console (on a non-trusted system) +since such a session may provide single-user access. +.PP +In the non-interactive mode +.B console +outputs only the requested information. +.SH OPTIONS +.TP +.B \-a +Access a console with a two-way connection (this is the default). +.TP +.B \-d +Display daemon versions. The \fIconsole\fP client connects to each +server to request its version information. The uppercase varient of +this option only requests the primary server's version. +.TP +.BI \-e esc +Set the initial two character escape sequence to +those represented by \fIesc\fP. +Any of the forms output by \fIcat\fP(1)'s \-\fBv\fP option +are accepted. The default value is ``^Ec''. +.TP +.B \-f +Same as +.I \-a +except it will force any existing connection into spy mode. +.TP +.B \-h +Display a brief help message. +.TP +.BI \-M server +The \fIconsole\fP client program polls \fIserver\fP as the primary server, +rather than the hard coded default (``console.cc.purdue.edu''). +.TP +.B \-q +The \fIconsole\fP client requests the server daemon quit (shutdown). +A password is sent in the protocol stream, if none is required for +the local host to shutdown the server just press return. The uppercase +varient of this command just acts on the primary server. +.TP +.B \-r +Request a raw connection to the group control virtual console, +this is only useful for learning the protocol used by the +interactive sequence. +.TP +.B \-s +Requests a read-only (spy mode) connection. +If this mode all the escape sequences (below) work, or report errors, +but all other keyboard input is discarded. +.TP +.B \-V +Output the version of the console client program. +.TP +.B \-v +Be more verbose during when building the connection(s). +Use this option in combination with any of `show' options (below) +for added benefit. +.TP +.B \-u +Show a list of consoles and the users on each. +.TP +.B \-w +Show a list of all connections to all consoles. +.TP +.B \-x +Show a list of consoles and devices. +.PP +The \-\fBA\fP, \-\fBF\fP, or \-\fBS\fP 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. +.PP +Any default (\-\fBa\fP) connection is dropped to spy mode if +someone else is attached read-write. +.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'' +(octal 005 143). Commands are: +.sp +.TS +c l. +a switch to attach mode +c toggle flow control (don't do this) +d down the current console +e change the escape sequence to the next two characters +f force a switch to attach mode +l1 send a 3 second serial line break (might halt a Sun) +o reopen the line to clear errors (silo overflows) +r replay the last 20 lines of output +s switch to spy mode +u show other users on this port +v show the version of the group server +w who is using this console +x examine this group's devices and modes. +z suspend this connection +? display list of commands +^I toggle tab expansion +^J continue, ignore the escape sequence +^R replay the last line only +\. disconnect +; provide a new login or shift to a new console ++(-) be more (less) free with newlines +.TE +.sp +.PP +If any other character is hit after the escape sequence, all three characters +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. +.PP +In the \-u output, the login \fB\fP indicates no one is +viewing that console, the login \fB\fP 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. +.SH EXAMPLES +.TP +console \-u +Outputs something like: +.sp +.RS +.TS +l18 l l. +dumb up +expert up ksb@mentor +tyro up +mentor up +sage up fine@cis +.TE +.RE +.sp +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, +other \fIlogin\fP@\fIhost\fP entries are the currently attached +\fIsage\fP and \fIexpert\fP. +.TP +console \-w +Outputs something like: +.sp +.RS +.TS +l l l. +ksb@extra on expert Fri Feb 15 16:40:36 1991 +file@cis on sage Thu Feb 14 1:04:10 1991 +dmr@alice spy tyro Thu Feb 7 10:09:59 1991 +.TE +.RE +.sp +.TP +console \-e \*(lq^[1\*(rq lv426 +Requests a connection to the host ``lv426'' with the escape characters +set to ``escape one''. +.SH BUGS +Connections suspended under Dynix sometimes break the kernel when +resumed. Suspended connections are a poor idea in general, just +disconnect instead. +.PP +It is possible to create a loop of console connections, with ugly results. +Never run \fIconsole\fP from within a console connection. +.PP +The \-\fBr\fP option doesn't help to explain how connections get built. +.SH AUTHORS +Thomas A. Fine, Ohio State Computer Science. +.br +Kevin Braunsdorf, Purdue University Computing Center +.SH "SEE ALSO" +conserver.cf(5L), conserver(8L) diff --git a/console/console.c b/console/console.c new file mode 100644 index 0000000..2afb73b --- /dev/null +++ b/console/console.c @@ -0,0 +1,1317 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cons.h" +#include "version.h" + +#if USE_STRINGS +#include +#else +#include +#endif + +#if USE_TERMIOS +#include +#include + +#else +#if USE_TERMIO +#include + +#else /* use ioctl stuff */ +#include +#include +#endif +#endif + +#if !defined IBMR2 +extern char *strrchr(), *strchr(); +#endif +extern char *getenv(); +extern char *getpass(); +extern char *calloc(), *realloc(); +/* extern short htons(); */ +extern int errno; + +#if !HAVE_STRERROR +extern char *sys_errlist[]; +#define strerror(Me) (sys_errlist[Me]) +#endif + +static char rcsid[] = + "$Id: console.c,v 5.20 1998-11-20 16:53:02-08 bryan Exp $"; +static char *progname = + rcsid; +int fVerbose = 0, fReplay = 0, fRaw = 0; +int chAttn = -1, chEsc = -1; +char *pcInMaster = /* which machine is current */ + HOST; + +/* panic -- we have no more momory + */ +static void +OutOfMem() +{ + static char acNoMem[] = ": out of memory\n"; + + write(2, progname, strlen(progname)); + write(2, acNoMem, sizeof(acNoMem)-1); + exit(1); +} + +/* + * remove from "host1" those domains common to "host1" and "host2" + */ +static char * +whittle(host1, host2) +char *host1, *host2; +{ + char *p1, *p2; + + p1 = strchr(host1, '.'); + p2 = strchr(host2, '.'); + while (p1 != (char*)0 && p2 != (char*)0) { + if (strcmp(p1+1, p2+1) == 0) { + *p1 = '\000'; + break; + } + p1 = strchr(p1+1, '.'); + p2 = strchr(p2+1, '.'); + } + return host1; +} + +static char + acMesg[8192+2], /* the buffer for startup negotiation */ + acLocalhost[] = /* the loopback device */ + "localhost", + acThisHost[256], /* what the remote host would call us */ + acMyName[256]; /* what we call ourselves */ +static struct sockaddr_in + local_port; /* the looback address, if local use it */ + +/* output a control (or plain) character as a UNIX user would expect it (ksb) + */ +static void +putCtlc(c, fp) +int c; +FILE *fp; +{ + if (0 != (0200 & c)) { + (void)putc('M', fp); + (void)putc('-', fp); + c &= ~0200; + } + if (isprint(c)) { + (void)putc(c, fp); + return; + } + (void)putc('^', fp); + if (c == 0177) { + (void)putc('?', fp); + return; + } + (void)putc(c+0100, fp); +} + +static char *apcLong[] = { + "a(A) attach politelty (and replay last 20 lines)", + "d(D) display (local) daemon version", + "e esc set the initial escape characters", + "f(F) force read/write connection (and replay)", + "h output this message", + "l user use username instead of current username", + "M mach master server to poll first", + "q(Q) send a quit command to the (local) server", + "r connect to the console group only", + "s(S) spy on a console (and replay)", + "u show users on the various consoles", + "v be more verbose", + "V show version information", + "w show who is on which console", + "x examine ports and baud rates", + (char *)0 +}; + +/* output a long message to the user + */ +static void +Usage(fp, ppc) +FILE *fp; +char **ppc; +{ + for (/* passed */; (char *)0 != *ppc; ++ppc) + (void)fprintf(fp, "%s\n", *ppc); +} + +/* expain who we are and which revision we are (ksb) + */ +static void +Version() +{ + register unsigned char *puc; + + printf("%s: %s\n", progname, GNAC_VERSION); + printf("%s: initial master server `%s\'\n", progname, pcInMaster); + printf("%s: default escape sequence `", progname); + putCtlc(DEFATTN, stdout); + putCtlc(DEFESC, stdout); + printf("\'\n"); + puc = (unsigned char *)&local_port.sin_addr; + printf("%s: loopback address for %s is %d.%d.%d.%d\n", progname, acMyName, puc[0], puc[1], puc[2], puc[3]); +} + + +/* convert text to control chars, we take `cat -v' style (ksb) + * ^X (or ^x) contro-x + * M-x x plus 8th bit + * c a plain character + */ +static int +ParseChar(ppcSrc, pcOut) +char **ppcSrc, *pcOut; +{ + register int cvt, n; + register char *pcScan = *ppcSrc; + + if ('M' == pcScan[0] && '-' == pcScan[1] && '\000' != pcScan[2]) { + cvt = 0x80; + pcScan += 2; + } else { + cvt = 0; + } + + if ('\000' == *pcScan) { + return 1; + } + + if ('^' == (n = *pcScan++)) { + if ('\000' == (n = *pcScan++)) { + return 1; + } + if (islower(n)) { + n = toupper(n); + } + if ('@' <= n && n <= '_') { + cvt |= n - '@'; + } else if ('?' == *pcScan) { + cvt |= '\177'; + } else { + return 1; + } + } else { + cvt |= n; + } + + if ((char *)0 != pcOut) { + *pcOut = cvt; + } + *ppcSrc = pcScan; + return 0; +} + +/* find the two characters that makeup the users escape sequence (ksb) + */ +static void +ParseEsc(pcText) +char *pcText; +{ + auto char *pcTemp; + auto char c1, c2; + + pcTemp = pcText; + if (ParseChar(&pcTemp, &c1) || ParseChar(&pcTemp, &c2)) { + fprintf(stderr, "%s: poorly formed escape sequence `%s\'\n", progname, pcText); + exit(3); + } + if ('\000' != *pcTemp) { + fprintf(stderr, "%s: too many characters in new escape sequence at ...`%s\'\n", progname, pcTemp); + exit(3); + } + chAttn = c1; + chEsc = c2; +} + + +/* set the port for socket connection (ksb) + * return the fd for the new connection; if we can use the loopback, do + * as a side effect we set ThisHost to a short name for this host + */ +int +GetPort(pcToHost, pPort, sPort) +char *pcToHost; +struct sockaddr_in *pPort; +short sPort; +{ + register int s; + register struct hostent *hp; + +#if USE_STRINGS + (void)bzero((char *)pPort, sizeof(*pPort)); +#else + memset((void *)pPort, '\000', sizeof(*pPort)); +#endif + if (0 == strcmp(pcToHost, strcpy(acThisHost, acMyName))) { + (void)strcpy(pcToHost, acLocalhost); +#if USE_STRINGS + (void)bcopy((char *)&local_port.sin_addr, (char *)&pPort->sin_addr, sizeof(local_port.sin_addr)); +#else + memcpy((char *)&pPort->sin_addr, (char *)&local_port.sin_addr, sizeof(local_port.sin_addr)); +#endif + } else if ((struct hostent *)0 != (hp = gethostbyname(pcToHost))) { +#if USE_STRINGS + (void)bcopy((char *)hp->h_addr, (char *)&pPort->sin_addr, hp->h_length); +#else + memcpy((char *)&pPort->sin_addr, (char *)hp->h_addr, hp->h_length); +#endif + } else { + fprintf(stderr, "%s: gethostbyname: %s: %s\n", progname, pcToHost, hstrerror(h_errno)); + exit(9); + } + pPort->sin_port = sPort; + pPort->sin_family = AF_INET; + + /* make hostname short, if we are calling ourself, chop at first dot + if (0 == strcmp(pcToHost, acLocalhost)) { + register char *pcChop; + if ((char *)0 != (pcChop = strchr(acThisHost, '.'))) { + *pcChop = '\000'; + } + } else { + (void)whittle(acThisHost, pcToHost); + } + */ + + /* set up the socket to talk to the server for all consoles + * (it will tell us who to talk to to get a real connection) + */ + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "%s: socket: %s\n", progname, strerror(errno)); + exit(1); + } + if (connect(s, (struct sockaddr *)pPort, sizeof(*pPort)) < 0) { + fprintf(stderr, "%s: connect: %d@%s: %s\n", progname, ntohs(pPort->sin_port), pcToHost, strerror(errno)); + exit(1); + } + + return s; +} + + +/* the next two routines assure that the users tty is in the + * correct mode for us to do our thing + */ +static int screwy = 0; +#if USE_TERMIOS +static struct termios o_tios; +#else +#if USE_TERMIO +static struct termio o_tio; +#else +static struct sgttyb o_sty; +static struct tchars o_tchars; +static struct ltchars o_ltchars; +#endif +#endif + + +/* + * 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 +c2raw() +{ +#if USE_TERMIOS + auto struct termios n_tios; +#else +#if USE_TERMIO + auto struct termio n_tio; +#else + auto struct sgttyb n_sty; + auto struct tchars n_tchars; + auto struct ltchars n_ltchars; +#endif +#endif + + if (!isatty(0) || 0 != screwy) + return; + +#if USE_TERMIOS + if (0 != ioctl(0, TCGETS, & o_tios)) { + fprintf(stderr, "%s: iotcl: getsw: %s\n", progname, strerror(errno)); + exit(10); + } + 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); + n_tios.c_cc[VMIN] = 1; + n_tios.c_cc[VTIME] = 0; + if (0 != ioctl(0, TCSETS, & n_tios)) { + fprintf(stderr, "%s: getarrt: %s\n", progname, strerror(errno)); + exit(10); + } +#else +#if USE_TERMIO + if (0 != ioctl(0, TCGETA, & o_tio)) { + fprintf(stderr, "%s: iotcl: geta: %s\n", progname, strerror(errno)); + exit(10); + } + 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); + n_tio.c_cc[VMIN] = 1; + n_tio.c_cc[VTIME] = 0; + if (0 != ioctl(0, TCSETAF, & n_tio)) { + fprintf(stderr, "%s: iotcl: seta: %s\n", progname, strerror(errno)); + exit(10); + } +#else + if (0 != ioctl(0, TIOCGETP, (char *)&o_sty)) { + fprintf(stderr, "%s: iotcl: getp: %s\n", progname, strerror(errno)); + exit(10); + } + 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)) { + fprintf(stderr, "%s: iotcl: setp: %s\n", progname, strerror(errno)); + exit(10); + } + + /* stty undef all tty chars + */ + if (-1 == ioctl(0, TIOCGETC, (char *)&n_tchars)) { + fprintf(stderr, "%s: ioctl: getc: %s\n", progname, 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)) { + fprintf(stderr, "%s: ioctl: setc: %s\n", progname, strerror(errno)); + return; + } + if (-1 == ioctl(0, TIOCGLTC, (char *)&n_ltchars)) { + fprintf(stderr, "%s: ioctl: gltc: %s\n", progname, 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)) { + fprintf(stderr, "%s: ioctl: sltc: %s\n", progname, strerror(errno)); + return; + } +#endif +#endif + screwy = 1; +} + +/* + * put the tty back as it was, however that was + */ +static void +c2cooked() +{ + if (!screwy) + return; +#if USE_TERMIOS + (void)ioctl(0, TCSETS, (char *)&o_tios); +#else +#if USE_TERMIO + (void)ioctl(0, TCSETA, (char *)&o_tio); +#else + (void)ioctl(0, TIOCSETP, (char *)&o_sty); + (void)ioctl(0, TIOCSETC, (char *)&o_tchars); + (void)ioctl(0, TIOCSLTC, (char *)&o_ltchars); +#endif +#endif + screwy = 0; +} + + + +/* send out some data along the connection (ksb) + */ +static void +SendOut(fd, pcBuf, iLen) +int fd, iLen; +char *pcBuf; +{ + register int nr; + + while (0 != iLen) { + if (-1 == (nr = write(fd, pcBuf, iLen))) { + c2cooked(); + fprintf(stderr, "%s: lost connection\n", progname); + exit(3); + } + iLen -= nr; + pcBuf += nr; + } +} + +/* read a reply from the console server (ksb) + * if pcWnat == (char *)0 we strip \r\n from the and and return strlen + */ +static int +ReadReply(fd, pcBuf, iLen, pcWant) +int fd, iLen; +char *pcBuf, *pcWant; +{ + register int nr, j, iKeep; + + iKeep = iLen; + for (j = 0; j < iLen; /* j+=nr */) { + switch (nr = read(fd, &pcBuf[j], iLen-1)) { + case 0: + if (iKeep != iLen) { + break; + } + /* fall through */ + case -1: + c2cooked(); + fprintf(stderr, "%s: lost connection\n", progname); + exit(3); + default: + j += nr; + iLen -= nr; + if ('\n' == pcBuf[j-1]) { + pcBuf[j] = '\000'; + break; + } + if (0 == iLen) { + c2cooked(); + fprintf(stderr, "%s: reply too long\n", progname); + exit(3); + } + 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(pcBuf[j-1])) { + pcBuf[--j] = '\000'; + } + return j; + } + return strcmp(pcBuf, pcWant); +} + +#if defined(SERVICE) +static struct servent *pSE; +#endif + +/* 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 +Gather(pfi, pcPorts, pcMaster, pcTo, pcCmd, pcWho) +int (*pfi)(); +char *pcPorts, *pcMaster, *pcTo, *pcCmd, *pcWho; +{ + register int s; + register short j; + register char *pcNext, *pcServer; + auto char acExcg[256]; + auto struct sockaddr_in client_port; + auto int iRet = 0; + + for (/* param */; '\000' != *pcPorts; pcPorts = pcNext) { + if ((char *)0 == (pcNext = strchr(pcPorts, ':'))) + pcNext = ""; + else + *pcNext++ = '\000'; + + (void)strcpy(acExcg, pcMaster); + if ((char *)0 != (pcServer = strchr(pcPorts, '@'))) { + *pcServer++ = '\000'; + if ('\000' != *pcServer) { + (void)strcpy(acExcg, pcServer); + } + } + + if ('\000' == *pcPorts) { +#if defined(SERVICE) + /* in net order -- ksb */ + j = pSE->s_port; +#else +#if defined(PORT) + j = htons(PORT); +#else + fprintf(stderr, "%s: no port or service compiled in?\n", progname); + exit(8); +#endif +#endif + } else if (!isdigit(pcPorts[0])) { + fprintf(stderr, "%s: %s: %s\n", progname, pcMaster, pcPorts); + exit(2); + } else { + j = htons((short)atoi(pcPorts)); + } + + s = GetPort(acExcg, & client_port, j); + + if (0 != ReadReply(s, acMesg, sizeof(acMesg), "ok\r\n")) { + fprintf(stderr, "%s: %s: %s", progname, acExcg, acMesg); + exit(4); + } + + iRet += (*pfi)(s, acExcg, pcTo, pcCmd, pcWho); + (void)close(s); + if ((char *)0 != pcServer) { + *pcServer = '@'; + } + } + return iRet; +} + + +static int SawUrg = 0; + +/* when the conserver program gets the suspend sequence it will send us + * an out of band command to suspend ourself. We just tell the reader + * routine we saw one + */ +SIGRETS +oob(sig) +int sig; +{ + ++SawUrg; +} + + +/* interact with a group server (ksb) + */ +static int +CallUp(s, pcMaster, pcMach, pcHow, pcUser) +int s; +char *pcMaster, *pcMach, *pcHow, *pcUser; +{ + register int nc; + register int fIn; + auto fd_set rmask, rinit; + extern int atoi(); + + if (fVerbose) { + printf("%s: %s to %s (%son %s)\n", progname, pcHow, pcMach, fRaw ? "raw " : "", pcMaster); + } +#if defined(F_SETOWN) + if (-1 == fcntl(s, F_SETOWN, getpid())) { + fprintf(stderr, "%s: fcntl: %d: %s\n", progname, s, strerror(errno)); + } +#else +#if defined(SIOCSPGRP) + { + auto int iTemp; + /* on the HP-UX systems if different + */ + iTemp = -getpid(); + if (-1 == ioctl(s, SIOCSPGRP, & iTemp)) { + fprintf(stderr, "%s: ioctl: %d: %s\n", progname, s, strerror(errno)); + } + } +#endif +#endif +#if defined(SIGURG) + (void)signal(SIGURG, oob); +#endif + + /* change escape sequence (if set on the command line) + * and replay the log for the user, if asked + */ + if (chAttn == -1 || chEsc == -1) { + chAttn = DEFATTN; + chEsc = DEFESC; + } else { + /* tell the conserver to change escape sequences, assmue OK + * (we'll find out soon enough) + */ + (void)sprintf(acMesg, "%c%ce%c%c", DEFATTN, DEFESC, chAttn, chEsc); + SendOut(s, acMesg, 5); + if (0 == ReadReply(s, acMesg, sizeof(acMesg), (char *)0)) { + fprintf(stderr, "protocol botch on redef on escape sequence\n"); + exit(8); + } + } + 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) { + /* begin connect with who we are + */ + (void)sprintf(acMesg, "%c%c;", chAttn, chEsc); + SendOut(s, acMesg, 3); + if (0 != ReadReply(s, acMesg, sizeof(acMesg), "[login:\r\n") && 0 != strcmp(acMesg, "\r\n[login:\r\n")) { + fprintf(stderr, "%s: call: %s\n", progname, acMesg); + exit(2); + } + + (void)sprintf(acMesg, "%s@%s\n", pcUser, acThisHost); + SendOut(s, acMesg, strlen(acMesg)); + if (0 != ReadReply(s, acMesg, sizeof(acMesg), "host:\r\n")) { + fprintf(stderr, "%s: %s\n", progname, acMesg); + exit(2); + } + + /* which host we want, and a passwd if asked for one + */ + (void)sprintf(acMesg, "%s\n", pcMach); + SendOut(s, acMesg, strlen(acMesg)); + (void)ReadReply(s, acMesg, sizeof(acMesg), (char *)0); + if (0 == strcmp(acMesg, "passwd:")) { + auto char pass[32]; + (void)sprintf(acMesg, "Enter %s's password:", pcUser); + (void)strcpy(pass, getpass(acMesg)); + (void)sprintf(acMesg, "%s\n", pass); + SendOut(s, acMesg, strlen(acMesg)); + (void)ReadReply(s, 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 = '-'; + fprintf(stderr, "%s: %s is down\n", progname, 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 = '-'; + fprintf(stderr, "%s: %s is a control port\n", progname, pcMach); + if (fVerbose) { + printf("[use `"); + putCtlc(chAttn, stdout); + putCtlc(chEsc, stdout); + printf(";\' to open a console line]\n"); + } + } else { + fprintf(stderr, "%s: %s: %s\n", progname, pcMach, acMesg); + exit(5); + } + } + + printf("[Enter `"); + putCtlc(chAttn, stdout); + putCtlc(chEsc, stdout); + printf("?\' for help]\n"); + + /* if the host is not down, finish the connection, and force + * the correct attachment for the user + */ + if ('-' != fIn) { + if (fIn == 'r') { + if ('s' != *pcHow) { + fprintf(stderr, "%s: %s is read-only\n", progname, pcMach); + } + } else if (fIn != ('f' == *pcHow ? 'a' : *pcHow)) { + (void)sprintf(acMesg, "%c%c%c", chAttn, chEsc, *pcHow); + SendOut(s, acMesg, 3); + } + if (fReplay) { + (void)sprintf(acMesg, "%c%cr", chAttn, chEsc); + SendOut(s, acMesg, 3); + } else if (fVerbose) { + (void)sprintf(acMesg, "%c%c\022", chAttn, chEsc); + SendOut(s, acMesg, 3); + } + } + (void)fflush(stdout); + (void)fflush(stderr); + + c2raw(); + + /* read from stdin and the socket (non-blocking!). + * rmask indicates which descriptors to read from, + * the others are not used, nor is the result from + * select, read, or write. + */ + FD_ZERO(& rinit); + FD_SET(s, &rinit); + FD_SET(0, &rinit); + for (;;) { + /* 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)) { + static char acCmd[64]; + + rmask = rinit; + + /* if we were suspened, try again */ + if (EINTR != errno || !SawUrg) { + continue; + } + SawUrg = 0; +#if defined(SIGURG) + (void)signal(SIGURG, oob); +#endif + + /* get the pending urgent message + */ + while (recv(s, acCmd, 1, MSG_OOB) < 0) { + switch (errno) { + case EWOULDBLOCK: + /* clear any pending input to make room */ + (void)read(s, acCmd, sizeof(acCmd)); + CSTROUT(1, "."); + continue; + case EINVAL: + default: + fprintf(stderr, "%s: recv: %d: %s\r\n", progname, s, strerror(errno)); + sleep(1); + continue; + } + } + switch (acCmd[0]) { + case OB_SUSP: +#if defined(SIGSTOP) + CSTROUT(1, "stop]"); + c2cooked(); + (void)kill(getpid(), SIGSTOP); + c2raw(); + CSTROUT(1, "[press any character to continue"); +#else + CSTROUT(1, "stop not supported -- press any character to continue"); +#endif + break; + case OB_DROP: + CSTROUT(1, "dropped by server]\r\n"); + c2cooked(); + exit(1); + /*NOTREACHED*/ + default: + fprintf(stderr, "%s: unknown out of band command `%c\'\r\n", progname, acCmd[0]); + (void)fflush(stderr); + break; + } + } + + /* anything from socket? */ + if (FD_ISSET(s, &rmask)) { + if ((nc = read(s, acMesg, sizeof(acMesg))) == 0) { + break; + } +#if STRIP8 + /* clear parity? */ + for (i = 0; i < nc; ++i) + acMesg[i] &= 127; +#endif + SendOut(1, acMesg, nc); + } + /* anything from stdin? */ + if (FD_ISSET(0, &rmask)) { + if ((nc = read(0, acMesg, sizeof(acMesg))) == 0) + break; + SendOut(s, acMesg, nc); + } + } + c2cooked(); + if (fVerbose) + printf("Console %s closed.\n", pcMach); + 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 + */ +static int +Indir(s, pcMaster, pcMach, pcCmd, pcWho) +int s; +char *pcMaster, *pcMach, *pcCmd, *pcWho; +{ + auto char acPorts[4097]; + + /* send request for master list + */ + (void)sprintf(acPorts, "call:%s\r\n", pcMach); + SendOut(s, acPorts, strlen(acPorts)); + + /* get the ports number */ + if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { + fprintf(stderr, "%s: master forward broken\n", progname); + exit(1); + } + + if ('@' == acPorts[0]) { + static int iLimit = 0; + if (iLimit++ > 10) { + fprintf(stderr, "%s: forwarding level too deep!\n", progname); + 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 (MAXGRP*80) +#define BUF_MIN 80 +#define BUF_CHUNK (2*132) + +/* Cmd is implemented seperately 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. + */ +/*ARGSUSED*/ +static int +Cmd(s, pcMaster, pcMach, pcCmd, pcWho) +int s; +char *pcMaster, *pcMach, *pcCmd, *pcWho; +{ + static int iMax = 0; + static char *pcBuf = (char *)0; + register int nr, iRem, i, fBrace; + + /* 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(); + } + } + + /* send sign-on stuff, then wait for a reply, like "ok\r\n" + * before allowing a write + */ + (void)sprintf(acMesg, "%c%c%c%c%c.", DEFATTN, DEFESC, *pcCmd, DEFATTN, DEFESC); + SendOut(s, acMesg, 9); + + /* 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 = read(s, pcBuf+i, iRem))) { + i += nr; + iRem -= nr; + if (iRem >= BUF_MIN) { + continue; + } + iMax += BUF_CHUNK; + if ((char *)0 == (pcBuf = realloc(pcBuf, iMax))) { + OutOfMem(); + } + 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; + } + continue; + } + switch (pcBuf[nr]) { + case '\r': + if (0 == iRem) + continue; + break; + case '\n': + if (0 == iRem) + continue; + (void)putchar('\n'); + iRem = 0; + continue; + case '[': + fBrace = 1; + continue; + } + (void)putchar(pcBuf[nr]); + iRem = 1; + } + /* (void)SendOut(1, pcBuf, i); */ + (void)fflush(stdout); + + return 0; +} + +/* the masters tell us the group masters with a "groups" command (ksb) + */ +static int +CmdGroup(s, pcMaster, pcMach, pcCmd, pcWho) +int s; +char *pcMaster, *pcMach, *pcCmd, *pcWho; +{ + auto char acPorts[4097]; + + /* send request for master list + */ + (void)sprintf(acPorts, "groups\r\n", pcCmd); + SendOut(s, acPorts, strlen(acPorts)); + + /* get the ports number */ + if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { + fprintf(stderr, "%s: master forward broken\n", progname); + exit(1); + } + 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 +CmdMaster(s, pcMaster, pcMach, pcCmd, pcWho) +int s; +char *pcMaster, *pcMach, *pcCmd, *pcWho; +{ + auto char acPorts[4097]; + + /* send request for master list + */ + CSTROUT(s, "master\r\n"); + + /* get the ports number */ + if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { + fprintf(stderr, "%s: master forward broken\n", progname); + exit(1); + } + /* 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. + */ +/*ARGSUSED*/ +static int +Ctl(s, pcMaster, pcMach, pcCmd, pcWho) +int s; +char *pcMaster, *pcMach, *pcCmd, *pcWho; +{ + auto char acPorts[4097]; + + /* send request for master list + */ + (void)sprintf(acPorts, "%s:%s\r\n", pcCmd, pcMach); + SendOut(s, acPorts, strlen(acPorts)); + + /* get the ports number */ + if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { + fprintf(stderr, "%s: group leader died?\n", progname); + 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 +CtlMaster(s, pcMaster, pcMach, pcCmd, pcWho) +int s; +char *pcMaster, *pcMach, *pcCmd, *pcWho; +{ + auto char acPorts[4097]; + + /* send request for master list + */ + CSTROUT(s, "master\r\n"); + + /* get the ports number */ + if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { + fprintf(stderr, "%s: master forward broken\n", progname); + exit(1); + } + /* 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 + * parse the cmd line, + * (optionally) get a shutdown passwd + * Gather results + * exit happy or sad + */ +int +main(argc, argv) +int argc; +char **argv; +{ + register struct hostent *hp; + register char *ptr, *pcCmd, *pcTo; + register struct passwd *pwdMe; + auto int opt; + auto int fLocal; + auto char acPorts[1024]; + auto char *pcUser; + auto int (*pfiCall)(); + static char acOpts[] = "aAdDsSfFe:hl:M:pvVwWUqQrux"; + extern long atol(); + extern int optind; + extern char *optarg; + + if ((char *)0 == (progname = strrchr(argv[0], '/'))) { + progname = argv[0]; + } else { + ++progname; + } + +#if defined(SERVICE) + if ((struct servent *)0 == (pSE = getservbyname(SERVICE, "tcp"))) { + fprintf(stderr, "%s: getservbyname: %s: %s\n", progname, SERVICE, strerror(errno)); + exit(1); + } +#endif + + if (((char *)0 != (ptr = getenv("USER")) || (char *)0 != (ptr = getenv("LOGNAME"))) && + (struct passwd *)0 != (pwdMe = getpwnam(ptr)) && + getuid() == pwdMe->pw_uid) { + /* use the login $USER is set to, if it is our (real) uid */; + } else if ((struct passwd *)0 == (pwdMe = getpwuid(getuid()))) { + fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, getuid(), strerror(errno)); + exit(1); + } + pcUser = pwdMe->pw_name; + + /* get the out hostname and the loopback devices IP address + * (for trusted connections mostly) + */ + if (-1 == gethostname(acMyName, sizeof(acMyName)-1)) { + fprintf(stderr, "%s: gethostname: %s\n", progname, strerror(errno)); + exit(2); + } + if ((struct hostent *)0 != (hp = gethostbyname(acLocalhost))) { +#if USE_STRINGS + (void)bcopy((char *)hp->h_addr, (char *)&local_port.sin_addr, hp->h_length); +#else + memcpy((char *)&local_port.sin_addr, (char *)hp->h_addr, hp->h_length); +#endif + } else { + acLocalhost[0] = '\000'; + } + + /* command line parsing + */ + pcCmd = (char *)0; + fLocal = 0; + while (EOF != (opt = getopt(argc, argv, acOpts))) { + switch(opt) { + case 'A': /* attach with log replay */ + fReplay = 1; + /* fall through */ + case 'a': /* attach */ + pcCmd = "attach"; + break; + + case 'D': + fLocal = 1; + /*fallthrough*/ + case 'd': /* display daemon version */ + pcCmd = "version"; + break; + + case 'e': /* set escape chars */ + ParseEsc(optarg); + break; + + case 'F': /* force attach with log replay */ + fReplay = 1; + /* fall through */ + case 'f': /* force attach */ + pcCmd = "force"; + break; + + case 'M': + pcInMaster = optarg; + break; + + case 'l': + pcUser = optarg; + break; + + case 'r': + fRaw = 1; + if ((char *)0 == pcCmd) { + pcCmd = "spy"; + } + break; + + case 'S': /* spy with log replay */ + fReplay = 1; + /* fall through */ + case 's': /* spy */ + pcCmd = "spy"; + break; + + case 'u': + case 'U': + pcCmd = "users"; + break; + + case 'w': /* who */ + case 'W' : + pcCmd = "groups"; + break; + + case 'x': + pcCmd = "xamine"; + break; + + case 'p': /* send a pid command to the server */ + pcCmd = "pid"; + break; + + case 'Q': /* only quit this host */ + fLocal = 1; + /*fallthough*/ + case 'q': /* send quit command to server */ + pcCmd = "quit"; + break; + + case 'h': + printf("%s: usage [-aAfFsS] [-v] [-e esc] [-M mach] [-l username] machine\n", progname); + printf("%s: usage [-hpuVw]\n", progname); + printf("%s: usage [-qQ] [-v] [-M mach]\n", progname); + Usage(stdout, apcLong); + exit(0); + /*NOTREACHED*/ + + case 'v': + fVerbose = 1; + break; + + case 'V': + Version(); + exit(0); + + default: /* huh? */ + fprintf(stderr, "%s: unknown option `%c\', try -h\n", progname, opt); + exit(1); + /*NOTREACHED*/ + } + } + + /* finish resolving the command to do, call Gather + */ + if ((char *)0 == pcCmd) { + pcCmd = "attach"; + } + if ('a' == *pcCmd || 'f' == *pcCmd || 's' == *pcCmd) { + if (optind >= argc) { + fprintf(stderr, "%s: missing machine name\n", progname); + exit(1); + } + pcTo = argv[optind++]; + } else { + pcTo = "*"; + } + if (optind < argc) { + fprintf(stderr, "%s: extra garbage on command line? (%s...)\n", progname, argv[optind]); + exit(1); + } + (void)sprintf(acPorts, "@%s", pcInMaster); + if ('q' == *pcCmd) { + auto char acPass[32]; + (void)strcpy(acPass, getpass("Enter root password:")); + pfiCall = fLocal ? Ctl : CtlMaster; + pcTo = acPass; + } else if ('v' == *pcCmd) { + pfiCall = fLocal ? Ctl : CtlMaster; + } else if ('p' == *pcCmd) { + pfiCall = CtlMaster; + } else if ('a' == *pcCmd || 'f' == *pcCmd || 's' == *pcCmd) { + pfiCall = Indir; + } else { + pfiCall = CmdMaster; + } + exit(Gather(pfiCall, acPorts, pcInMaster, pcTo, pcCmd, pcUser)); +} diff --git a/console/console.man b/console/console.man new file mode 100644 index 0000000..9b63f3e --- /dev/null +++ b/console/console.man @@ -0,0 +1,185 @@ +.\" $Id: console.man,v 5.0 92/01/13 14:44:36 ksb Exp $ +.TH CONSOLE 8L "Local" +.SH NAME +console \- console server client program +.SH SYNOPSIS +\fBconsole\fP [\-\fBrv\fP] [\-\fBAFSafs\fP] [\-\fBe\fP \fIesc\fP] [\-\fBM\fP \fIserver\fP] \fIhost\fP +.br +\fBconsole\fP [\-\fBdDqQ\fP] [\-\fBv\fP] [\-\fBM\fP \fIserver\fP] \fIhost\fP +.br +\fBconsole\fP [\-\fBv\fP] [\-\fBhuVwx\fP] +.SH DESCRIPTION +.B Console +is used to manipulate console terminals remotely or poll running +\fIconserver\fP(8L) daemons for status information. +.PP +.B Console +queries the user for the root passwd before +granting interactive access to a console (on a non-trusted system) +since such a session may provide single-user access. +.PP +In the non-interactive mode +.B console +outputs only the requested information. +.SH OPTIONS +.TP +.B \-a +Access a console with a two-way connection (this is the default). +.TP +.B \-d +Display daemon versions. The \fIconsole\fP client connects to each +server to request its version information. The uppercase varient of +this option only requests the primary server's version. +.TP +.BI \-e esc +Set the initial two character escape sequence to +those represented by \fIesc\fP. +Any of the forms output by \fIcat\fP(1)'s \-\fBv\fP option +are accepted. The default value is ``^Ec''. +.TP +.B \-f +Same as +.I \-a +except it will force any existing connection into spy mode. +.TP +.B \-h +Display a brief help message. +.TP +.BI \-M server +The \fIconsole\fP client program polls \fIserver\fP as the primary server, +rather than the hard coded default (``console.cc.purdue.edu''). +.TP +.B \-q +The \fIconsole\fP client requests the server daemon quit (shutdown). +A password is sent in the protocol stream, if none is required for +the local host to shutdown the server just press return. The uppercase +varient of this command just acts on the primary server. +.TP +.B \-r +Request a raw connection to the group control virtual console, +this is only useful for learning the protocol used by the +interactive sequence. +.TP +.B \-s +Requests a read-only (spy mode) connection. +If this mode all the escape sequences (below) work, or report errors, +but all other keyboard input is discarded. +.TP +.B \-V +Output the version of the console client program. +.TP +.B \-v +Be more verbose during when building the connection(s). +Use this option in combination with any of `show' options (below) +for added benefit. +.TP +.B \-u +Show a list of consoles and the users on each. +.TP +.B \-w +Show a list of all connections to all consoles. +.TP +.B \-x +Show a list of consoles and devices. +.PP +The \-\fBA\fP, \-\fBF\fP, or \-\fBS\fP 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. +.PP +Any default (\-\fBa\fP) connection is dropped to spy mode if +someone else is attached read-write. +.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'' +(octal 005 143). Commands are: +.sp +.TS +c l. +a switch to attach mode +c toggle flow control (don't do this) +d down the current console +e change the escape sequence to the next two characters +f force a switch to attach mode +l1 send a 3 second serial line break (might halt a Sun) +o reopen the line to clear errors (silo overflows) +r replay the last 20 lines of output +s switch to spy mode +u show other users on this port +v show the version of the group server +w who is using this console +x examine this group's devices and modes. +z suspend this connection +? display list of commands +^I toggle tab expansion +^J continue, ignore the escape sequence +^R replay the last line only +\. disconnect +; provide a new login or shift to a new console ++(-) be more (less) free with newlines +.TE +.sp +.PP +If any other character is hit after the escape sequence, all three characters +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. +.PP +In the \-u output, the login \fB\fP indicates no one is +viewing that console, the login \fB\fP 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. +.SH EXAMPLES +.TP +console \-u +Outputs something like: +.sp +.RS +.TS +l18 l l. +dumb up +expert up ksb@mentor +tyro up +mentor up +sage up fine@cis +.TE +.RE +.sp +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, +other \fIlogin\fP@\fIhost\fP entries are the currently attached +\fIsage\fP and \fIexpert\fP. +.TP +console \-w +Outputs something like: +.sp +.RS +.TS +l l l. +ksb@extra on expert Fri Feb 15 16:40:36 1991 +file@cis on sage Thu Feb 14 1:04:10 1991 +dmr@alice spy tyro Thu Feb 7 10:09:59 1991 +.TE +.RE +.sp +.TP +console \-e \*(lq^[1\*(rq lv426 +Requests a connection to the host ``lv426'' with the escape characters +set to ``escape one''. +.SH BUGS +Connections suspended under Dynix sometimes break the kernel when +resumed. Suspended connections are a poor idea in general, just +disconnect instead. +.PP +It is possible to create a loop of console connections, with ugly results. +Never run \fIconsole\fP from within a console connection. +.PP +The \-\fBr\fP option doesn't help to explain how connections get built. +.SH AUTHORS +Thomas A. Fine, Ohio State Computer Science. +.br +Kevin Braunsdorf, Purdue University Computing Center +.SH "SEE ALSO" +conserver.cf(5L), conserver(8L)