rtty-4.0/0000755000175000017500000000000010024061643013503 5ustar noodlesnoodles00000000000000rtty-4.0/agelog.sh0000644000175000017500000001351510024061624015301 0ustar noodlesnoodles00000000000000#! /bin/sh # Copyright (c) 1996 by Internet Software Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS # ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE # CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. # (this is just a local copy to make sure it's available; master source for # this is elsewhere) # # $Id: agelog.sh,v 1.3 1996/08/23 22:25:25 vixie Exp $ # # agelog -- age log files, by Dave Lennert as told to Bob Desinger and # James Brister # # Usage: $0 [-m] [-p Bpid] [-s Bsig] logFile \ # [-p Apid] [-s Asig] howMany [stashDir] # # # The most recent logs are kept around by renaming logFile to # logFile.0, after similarly rolling logFile.0 => logFile.1 => logFile.2 => ... # If is named, the old logs will be kept in that directory. If not # given, the old logs are left in the same directory as the original logFile. # # Example: # `agelog /usr/adm/sulog 2' will, if run weekly, keep 3 files around: # /usr/adm/sulog containing this week's log info # /usr/adm/sulog.0 containing last week's log info # /usr/adm/sulog.1 containing the week before last's log info # # A typical crontab entry: # # Keep the most recent 2 weeks worth of uucp logs around in # # /tmp/Oldlogs/*, one per day, so that old LOGFILEs will be in # # /tmp/Oldlogs/LOGFILE.{0,1,2,...} # 00 1 * * * /usr/local/agelog /usr/spool/uucp/LOGFILE 14 /tmp/Oldlogs # # # Modification Tue Oct 9 16:48:56 1990 James Brister # # This now accepts some options: # -m if given before the log file name then mv will be used instead # of cp to move the file. # -p pid if given before the log file name then a signal will be # sent to the specified pid before the moves are done. # if given after the log file name then the signal is sent # after the moves. The default signal is HUP # -s sig if given before the log file name then the signal sent # before the move is changed from HUP to sig. If specified # after the log file name then the signal sent after the move # is changed from HUP to sig. # -h just displays the usage and exits. # # examples: # agelog -p 9999 somelog 3 # this will send a HUP signal to pid 9999 then save 3 # versions of the log files (using cp for the final move). # # agelog -m -p 8888 somelog -p 8888 4 # this will send a HUP signal to pid 8888 before saving the # 4 versions of the log files and then after. It will use mv # for the final move (not cp). # # agelog -p 7777 -s ALRM somelog -p 7777 2 # this will send a ALRM signal to pid 7777, then it will save # the log files, then it will send a HUP to pid 7777 # # NOTE: the changing of the BEFORE signal doesn't affect the AFTER # signal. Likewise with the pid's # # # set -vx # Initialize: PATH=/usr/ucb:/usr/bin:/bin:/etc:/usr/lib # BSD systems have /usr/ucb export PATH # traps: 0=exit 1=hangup 2=interrupt 3=quit 15=terminate trap 'echo 1>&2 "$0: Ow!"; exit 15' 1 2 3 15 MOVE=cp # default is to COPY log file, not MOVE it. ASIGNAL=HUP # signal to send AFTER the move/copy APID=0 # pid to send signal to AFTER the move/copy BSIGNAL=HUP # signal to send BEFORE the move/copy. BPID=0 # pid to send signal to BEFORE the move/copy USAGE="Usage: `basename $0` [-m] [-p Bpid] [-s Bsig] logFile [-p Apid] [-s Asig] howMany [stashDir]" # # Digest arguments: # # get the BEFORE arguments while [ `expr "$1" : '-.*'` -gt 0 ] do case "$1" in -h) echo $USAGE exit 0 ;; -m) MOVE=mv ;; -p) BPID=$2 shift ;; -s) BSIGNAL=$2 shift ;; -*) echo 1>&2 $USAGE exit 2 ;; esac shift done # now get the log file name if [ 0 -eq $# ] then echo $USAGE exit 2 else log="$1" # logFileName shift fi # now get the AFTER arguments while [ `expr "$1" : '-.*'` -gt 0 ] do case "$1" in -p) APID=$2 shift ;; -s) ASIGNAL=$2 shift ;; -*) echo 1>&2 $USAGE exit 2 ;; esac shift done # now get the numer of copies to save and the stash directory if [ 0 -eq $# ] then echo 1>&2 $USAGE exit 2 else max="$1" # howMany shift fi if [ 0 -eq $# ] then # no directory to stash them in; use log's directory head=`expr $log : '\(.*/\).*'` # /a/b/x => /a/b/ else # user specified a directory if [ ! -d "$1" ] then echo 1>&2 "$0: $1 is not a directory" exit 2 else head="$1/" fi fi # # Send signal if required BEFORE move # if [ 0 -ne $BPID ] then kill -$BSIGNAL $BPID fi # # Rename log.$max-1 => ... => log.3 => log.2 => log.1 # arch="${head}`basename $log`" # name of archive files, sans {.0, .1, ...} older=`expr $max - 1` # ensure we had a number in $2 if [ $? -eq 2 ] then # not a number, or some problem echo 1>&2 "$0: cannot decrement $max" exit 2 fi while [ $older -gt 0 ] do # age the logfiles in the stashdir old=`expr $older - 1` if [ -f $arch.$old ] then mv $arch.$old $arch.$older fi older=`expr $older - 1` done # # Old logfiles are all rolled over; now move the current log to log.0 # # Use cp instead of mv to retain owner & permissions for the original file, # and to avoid prematurely aging any info going into the file right now, # unless the user has given the -m option if [ -f $log ] then # don't create an old log if $2 was 0 test $max -gt 0 && $MOVE $log $arch.0 cp /dev/null $log # clear out log fi # # Now send signals if required # if [ 0 -ne $APID ] then kill -$ASIGNAL $APID fi exit 0 rtty-4.0/agelogs.sh0000644000175000017500000000202010024061624015451 0ustar noodlesnoodles00000000000000#! /bin/sh # $Id: agelogs.sh,v 1.4 2001/03/24 21:17:39 vixie Exp $ # Copyright (c) 1996 by Internet Software Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS # ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE # CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. agelog=DESTPATH/bin/agelog cd DESTPATH/dev for tty in * do $agelog -m DESTPATH/log/$tty \ -p `cat DESTPATH/pid/$tty` \ 7 \ DESTPATH/log/.aged done exit rtty-4.0/bitypes.h0000644000175000017500000000520710024061624015336 0ustar noodlesnoodles00000000000000/* * $Id: bitypes.h,v 1.3 1996/08/23 22:25:25 vixie Exp $ */ /* * Copyright (c) 1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef __BIT_TYPES_DEFINED__ # if (defined(BSD) && (BSD >= 199306)) || \ (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199312)) # define __BIT_TYPES_DEFINED__ # endif #endif #ifndef __BIT_TYPES_DEFINED__ #define __BIT_TYPES_DEFINED__ /* * Basic integral types. Omit the typedef if * not possible for a machine/compiler combination. */ typedef /*signed*/ char int8_t; typedef unsigned char u_int8_t; typedef short int16_t; typedef unsigned short u_int16_t; typedef int int32_t; typedef unsigned int u_int32_t; # if 0 /* don't fight with these unless you need them */ typedef long long int64_t; typedef unsigned long long u_int64_t; # endif #endif /* __BIT_TYPES_DEFINED__ */ rtty-4.0/connutil.c0000644000175000017500000000656410024061624015514 0ustar noodlesnoodles00000000000000/* rconnect - connect to a service on a remote host * vix 13sep91 [written - again, dammit] */ #ifndef LINT static char RCSid[] = "$Id: connutil.c,v 1.9 2001/03/24 21:14:25 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #ifdef WANT_TCPIP #include #include #include #include #include #include #include #include #include #include "rtty.h" #include "misc.h" extern int h_errno; extern char *ProgName; /* assume ip/tcp for now */ static jmp_buf jmpalrm; static void sigalrm(int); static int doconnect(struct sockaddr_in *n, int ns, int to) { int sock, ok, save; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { return -1; } if (to) { if (!setjmp(jmpalrm)) { signal(SIGALRM, sigalrm); alarm(to); } else { errno = ETIMEDOUT; goto finito; } } ok = (connect(sock, (struct sockaddr *)n, ns) >= 0); save = errno; finito: if (to) { alarm(0); signal(SIGALRM, SIG_DFL); } if (!ok) { close(sock); errno = save; return -1; } errno = save; return sock; } int rconnect(const char *host, const char *service, FILE *verbose, FILE *errors, int timeout) { u_int32_t **hp; struct hostent *h; struct sockaddr_in n; int port, sock, done; if (!(port = htons(atoi(service)))) { struct servent *s = getservbyname(service, "tcp"); if (!s) { if (errors) { fprintf(errors, "%s: unknown service\n", service); } errno = ENOPROTOOPT; return -1; } port = s->s_port; } n.sin_family = AF_INET; #ifndef NO_SOCKADDR_LEN n.sin_len = sizeof(struct sockaddr_in); #endif n.sin_port = port; if (inet_aton(host, &n.sin_addr)) { if (verbose) { fprintf(verbose, "trying [%s]\n", inet_ntoa(n.sin_addr.s_addr)); } done = ((sock = doconnect(&n, sizeof n, timeout)) >= 0); } else { h = gethostbyname(host); if (!h) { if (errors) { #ifndef NO_HSTRERROR fprintf(errors, "%s: %s\n", host, hstrerror(h_errno)); #else fprintf(errors, "%s: cannot resolve hostname\n", host); #endif } return -1; } for (hp = (u_int32_t**)h->h_addr_list; *hp; hp++) { bcopy(*hp, (caddr_t)&n.sin_addr.s_addr, h->h_length); if (verbose) { fprintf(verbose, "trying [%s]\n", inet_ntoa(**hp)); } if ((sock = doconnect(&n, sizeof n, timeout)) >= 0) { break; } } done = (*hp != NULL); } if (!done) { if (errors) { fprintf(errors, "%s: %s\n", host, strerror(errno)); } close(sock); return -1; } return sock; } static void sigalrm(int x) { longjmp(jmpalrm, 1); /*NOTREACHED*/ } #endif /*WANT_TCPIP*/ rtty-4.0/console.sh0000644000175000017500000000247610024061624015511 0ustar noodlesnoodles00000000000000#! /bin/sh # $Id: console.sh,v 1.5 2000/07/29 01:33:20 vixie Exp $ # Copyright (c) 1996 by Internet Software Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS # ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE # CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. default_options='' cmdopts='' while [ $# -gt 0 ]; do case $1 in -r) cmdopts="$opts -r"; shift ;; -*) shift ;; *) break 2 ;; esac done host=$1 [ -z "$host" ] && { ls DESTPATH/sock exit } if [ -s DESTPATH/opt/${host}.cons ]; then options=`cat DESTPATH/opt/${host}.cons` elif [ -s DESTPATH/opt/DEFAULT.cons ]; then options=`cat DESTPATH/opt/DEFAULT.cons` else options="$default_options" fi exec DESTPATH/bin/rtty $options $cmdopts DESTPATH/sock/$host rtty-4.0/locbrok.c0000644000175000017500000001476310024061624015314 0ustar noodlesnoodles00000000000000/* locbrok - location broker * vix 13sep91 [written] */ #ifndef LINT static char RCSid[] = "$Id: locbrok.c,v 1.9 2001/03/24 21:14:26 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #ifdef DEBUG int Debug = 0; #endif #ifdef WANT_TCPIP #include #include #include #include #include #include #include #include #include "rtty.h" #include "misc.h" #include "locbrok.h" #define USAGE_STR "[-s service] [-x debuglev]" /* misc.c */ #ifndef isnumber extern int isnumber(char *); #endif typedef struct reg_db { char *name; u_short port; u_short client; struct reg_db *next; } reg_db; static reg_db *find_byname(char *name), *find_byport(u_int port); static int add(char *name, u_int port, u_int client); static void server(void), client_input(int fd), rm_byclient(u_int client), print(void); static char *ProgName = "amnesia", *Service = LB_SERVNAME; static int Port, MaxFD; static fd_set Clients; static reg_db *RegDB = NULL; main(int argc, char *argv[]) { struct servent *serv; char ch; ProgName = argv[0]; while ((ch = getopt(argc, argv, "s:x:")) != EOF) { switch (ch) { case 's': Service = optarg; break; case 'x': Debug = atoi(optarg); break; default: USAGE((stderr, "%s: getopt=%c ?\n", ProgName, ch)); } } if (isnumber(Service) && (Port = atoi(Service))) { /* numeric service; we're ok */ ; } else if (NULL != (serv = getservbyname(Service, "tcp"))) { /* found the service name; we're ok */ Port = ntohs(serv->s_port); } else { /* nothing worked; use default */ Port = LB_SERVPORT; fprintf(stderr, "%s: service `%s' not found, using port %d\n", ProgName, Service, Port); } server(); } static void server(void) { int serv, on = 1; struct sockaddr_in name; serv = socket(PF_INET, SOCK_STREAM, 0); ASSERT(serv>=0, "socket") setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); name.sin_family = AF_INET; #ifndef NO_SOCKADDR_LEN name.sin_len = sizeof(struct sockaddr_in); #endif name.sin_addr.s_addr = INADDR_ANY; name.sin_port = htons(Port); ASSERT(bind(serv, (struct sockaddr *)&name, sizeof name)>=0, "bind") FD_ZERO(&Clients); MaxFD = serv; listen(serv, 5); for (;;) { fd_set readfds; int nset, fd; readfds = Clients; FD_SET(serv, &readfds); nset = select(MaxFD+1, &readfds, NULL, NULL, NULL); if (nset < 0 && errno == EINTR) continue; ASSERT(nset>=0, "assert") for (fd = 0; fd <= MaxFD; fd++) { if (!FD_ISSET(fd, &readfds)) continue; if (fd == serv) { int namesize = sizeof name; int addr, local, cl; ASSERT((cl=accept(serv, (struct sockaddr *)&name, &namesize))>=0, "accept") addr = ntohl(name.sin_addr.s_addr); local = (addr == INADDR_ANY) || ((IN_CLASSA(addr) && (addr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET); fprintf(stderr, "accept from %08x (%slocal)\n", addr, local?"":"not "); FD_SET(cl, &Clients); if (cl > MaxFD) MaxFD = cl; continue; } if (FD_ISSET(fd, &Clients)) { client_input(fd); } } } } static void client_input(int fd) { locbrok lb; reg_db *db; int keepalive = 0; if (0 >= read(fd, &lb, sizeof lb)) { fputs("locbrok.client_input: ", stderr); perror("read"); goto death; } lb.lb_port = ntohs(lb.lb_port); lb.lb_nlen = ntohs(lb.lb_nlen); if (lb.lb_nlen >= LB_MAXNAMELEN) { fprintf(stderr, "client_input: fd%d sent oversize req\n", fd); goto death; } lb.lb_name[lb.lb_nlen] = '\0'; fprintf(stderr, "client_input(fd %d, port %d, %d:`%s')\n", fd, lb.lb_port, lb.lb_nlen, lb.lb_name); if (lb.lb_port && !lb.lb_nlen) { if (NULL != (db = find_byport(lb.lb_port))) { lb.lb_nlen = min(strlen(db->name), LB_MAXNAMELEN); strncpy(lb.lb_name, db->name, lb.lb_nlen); } } else if (!lb.lb_port && lb.lb_nlen) { if (NULL != (db = find_byname(lb.lb_name))) { lb.lb_port = db->port; } } else if (lb.lb_port && lb.lb_nlen) { if (add(lb.lb_name, lb.lb_port, fd) == -1) { lb.lb_nlen = 0; } else { keepalive++; print(); } } else { fprintf(stderr, "bogus client_input (port,nlen both 0)\n"); goto death; } lb.lb_port = htons(lb.lb_port); lb.lb_nlen = htons(lb.lb_nlen); write(fd, &lb, sizeof lb); if (keepalive) return; death: close(fd); FD_CLR(fd, &Clients); rm_byclient(fd); print(); } static reg_db * find_byname(const char *name) { reg_db *db; for (db = RegDB; db; db = db->next) if (!strcmp(name, db->name)) return (db); return (NULL); } static reg_db * find_byport(u_int port) { reg_db *db; for (db = RegDB; db; db = db->next) if (port == db->port) return (db); return (NULL); } static int add(const char *name, u_int port, u_int client) { reg_db *db; if (find_byname(name) || find_byport(port)) return (-1); db = (reg_db *) safe_malloc(sizeof(reg_db)); db->name = safe_malloc(strlen(name)+1); strcpy(db->name, name); db->port = port; db->client = client; db->next = RegDB; RegDB = db; return (0); } static void rm_byclient(u_int client) { reg_db *cur = RegDB, *prev = NULL; while (cur) { if (cur->client == client) { reg_db *tmp = cur; if (prev) prev->next = cur->next; else RegDB = cur->next; cur = cur->next; free(tmp->name); free(tmp); } else { prev = cur; cur = cur->next; } } } static void print(void) { reg_db *db; fprintf(stderr, "db:\n"); for (db = RegDB; db; db = db->next) fprintf(stderr, "(%s %d %d)\n", db->name, db->port, db->client); fprintf(stderr, "---\n"); } #else /*WANT_TCPIP*/ #include int main(int argc, char *argv[]) { fprintf(stderr, "There is no location broker for this system.\n"); exit(1); } #endif /*WANT_TCPIP*/ rtty-4.0/locbrok.h0000644000175000017500000000216310024061624015310 0ustar noodlesnoodles00000000000000/* locbrok.h - defs for location broker * vix 13sep91 [written] * * $Id: locbrok.h,v 1.4 1996/08/23 22:25:25 vixie Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #define LB_SERVNAME "locbrok" #define LB_SERVPORT 160 #define LB_MAXNAMELEN 64 typedef struct locbrok { u_short lb_port; u_short lb_nlen; char lb_name[LB_MAXNAMELEN]; } locbrok; rtty-4.0/Makefile0000644000175000017500000000741310024061624015147 0ustar noodlesnoodles00000000000000# $Id: Makefile,v 1.17 2001/03/24 21:14:24 vixie Exp $ # Copyright (c) 1996,1997 by Internet Software Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS # ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE # CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. VERSION = 4.0 VPATH = ../src DESTROOT = DESTPATH = $(DESTROOT)/usr/local/rtty DESTBIN = $(DESTPATH)/bin #CC = cc CDEBUG = -O # # use -U to undefine, -D to define # DEBUG include code to help debug this software # WANT_TCP insecure network transparency # NEED_BITYPES_H if you aren't on BSD/386 1.1, BSD 4.4, or SGI IRIX5 # NEED_INET_ATON if your C library is pretty old wrt BSD 4.4 # NO_SOCKADDR_LEN if your "struct sockaddr_in" lacks a sin_len field # NO_HSTRERROR if your C library has no hstrerror() function # CDEFS = -DDEBUG -UWANT_TCPIP -UNEED_BITYPES_H -UNEED_INET_ATON \ -UNO_SOCKADDR_LEN -UNO_HSTRERROR # CFLAGS = $(CDEBUG) $(CDEFS) -I/usr/local/include LIBS = -lcrypt #(if WANT_TCPIP defined and this isn't in your libc) # -lresolv #(if the resolver needs it, which BIND>=4.9's will on BSD>=4.4 systems) # -l44bsd BINARY = ttysrv rtty locbrok SCRIPT = Startup console startsrv agelogs agelog ALL = $(BINARY) $(SCRIPT) all: $(ALL) clean: rm -f $(ALL) version.c rm -f *.o *.BAK *.CKP *~ kit:; shar README Makefile *.c *.h *.sh > kit bin.tar:; tar cf bin.tar $(ALL) install: $(ALL) Makefile -set -x; test -d $(DESTPATH) || mkdir $(DESTPATH) -set +e -x; for x in bin dev sock log pid opt out; do \ test -d $(DESTPATH)/$$x || mkdir $(DESTPATH)/$$x; \ done set -x; for x in $(BINARY); do \ install -c -m 111 $$x $(DESTBIN)/$$x; \ done set -x; for x in $(SCRIPT); do \ install -c -m 555 $$x $(DESTBIN)/$$x; \ done ttysrv: ttysrv.o ttyprot.o connutil.o misc.o version.o $(CC) -o ttysrv ttysrv.o ttyprot.o connutil.o misc.o version.o $(LIBS) rtty: rtty.o ttyprot.o connutil.o misc.o version.o $(CC) -o rtty rtty.o ttyprot.o connutil.o misc.o version.o $(LIBS) locbrok: locbrok.o misc.o version.o $(CC) -o locbrok locbrok.o misc.o version.o $(LIBS) console: console.sh Makefile sed -e 's:DESTPATH:$(DESTPATH):g' <$@.sh >$@ chmod +x $@ startsrv: startsrv.sh Makefile sed -e 's:DESTPATH:$(DESTPATH):g' <$@.sh >$@ chmod +x $@ agelogs: agelogs.sh Makefile sed -e 's:DESTPATH:$(DESTPATH):g' <$@.sh >$@ chmod +x $@ Startup: Startup.sh Makefile sed -e 's:DESTPATH:$(DESTPATH):g' <$@.sh >$@ chmod +x $@ agelog: agelog.sh Makefile cat <$@.sh >$@ chmod +x $@ ttysrv_saber:; #load $(CFLAGS) ttysrv.c ttyprot.c connutil.c rtty_saber:; #load $(CFLAGS) rtty.c ttyprot.c connutil.c locbrok_saber:; #load $(CFLAGS) locbrok.c ttysrv.o: Makefile ttysrv.c ttyprot.h rtty.h misc.h rtty.o: Makefile rtty.c ttyprot.h rtty.h misc.h ttyprot.o: Makefile ttyprot.c ttyprot.h rtty.h misc.h locbrok.o: Makefile locbrok.c locbrok.h rtty.h misc.h connutil.o: Makefile connutil.c rtty.h misc.h misc.o: Makefile misc.c rtty.h ttyprot.h misc.h version.c: Makefile rm -f version.c ( \ echo "#ifndef LINT"; \ echo "char Copyright[] ="; \ echo ' "Copyright 1996,1997,2001 by Internet Software Consortium, Inc.";'; \ echo "char Version[] ="; \ echo ' "Version $(VERSION) ('`whoami`'@'`hostname`' '`date`')";'; \ echo "#endif"; \ ) >version.c rtty-4.0/misc.c0000644000175000017500000000724210024061624014606 0ustar noodlesnoodles00000000000000/* misc.c - utility routines for the tty server * vixie 14may94 [cloned from ttyprot.c (12Sep91)] */ #ifndef LINT static char RCSid[] = "$Id: misc.c,v 1.7 2001/03/24 21:14:27 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "rtty.h" #include "misc.h" #include "ttyprot.h" #ifdef NEED_BITYPES_H # include "bitypes.h" #endif #include #if DEBUG extern int Debug; #endif void cat_v(FILE *file, const u_char *buf, int nchars) { while (nchars-- > 0) { int c = *buf++; if (isprint(c)) { fputc(c, file); } else if (iscntrl(c)) { fputc('^', file); fputc('@' + c, file); /* XXX assumes ASCII */ } else { fprintf(file, "\\%03o", c); } } } int install_ttyios(int tty, const struct termios *ios) { #ifdef DEBUG if (Debug) { fprintf(stderr, "install_termios(%d): C=0x%x L=0x%x I=0x%x O=0x%x m=%d t=%d\n", tty, ios->c_cflag, ios->c_lflag, ios->c_iflag, ios->c_oflag, ios->c_cc[VMIN], ios->c_cc[VTIME]); } #endif if (0 > tcsetattr(tty, TCSANOW, ios)) { perror("tcsetattr"); return (-1); } return (0); } void prepare_term(struct termios *ios, cc_t vmin) { ios->c_cflag |= HUPCL|CLOCAL|CREAD|TAUTOFLOW|CS8; ios->c_lflag |= NOFLSH; ios->c_lflag &= ~(ICANON|TOSTOP|ECHO|ECHOE|ECHOK|ECHONL|IEXTEN|ISIG); ios->c_iflag &= ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP |INLCR|IGNCR|ICRNL|IXON|IXOFF); ios->c_oflag &= ~OPOST; ios->c_cc[VMIN] = vmin; ios->c_cc[VTIME] = 0; } int tty_nonblock(int tty, int nonblock) { int old, new; old = fcntl(tty, F_GETFL, 0); if (old == -1) { perror("fcntl(F_GETFL)"); exit(1); } if (nonblock) new = old|O_NONBLOCK; else new = old & ~O_NONBLOCK; if (new != old) { if (fcntl(tty, F_SETFL, new) == -1) { perror("fcntl(F_SETFL)"); exit(1); } } return ((old & O_NONBLOCK) != 0); } void * safe_malloc(size_t size) { void *ret = malloc(size); if (!ret) { perror("malloc"); exit(1); } return (ret); } void * safe_calloc(size_t n, size_t size) { void *ret = calloc(n, size); if (!ret) { perror("calloc"); exit(1); } return (ret); } void * safe_realloc(void *ptr, size_t size) { void *ret = realloc(ptr, size); if (!ret) { perror("realloc"); exit(1); } return (ret); } char * safe_strdup(const char *str) { char *new = strdup(str); if (new == NULL) { perror("strdup"); exit(1); } return (new); } #ifndef isnumber /* * from libvixutil.a (14may94 version) */ int isnumber(const char *s) { char ch; int n; n = 0; while (ch = *s++) { n++; if (!isdigit(ch)) return (0); } return (n != 0); } #endif #ifdef NEED_INET_ATON int inet_aton(const char *cp, struct in_addr *addr) { u_int32_t v; if ((v = inet_addr(cp)) > 0) { addr->s_addr = v; return (1); } return (0); } #endif rtty-4.0/misc.h0000644000175000017500000000044510024061624014611 0ustar noodlesnoodles00000000000000void cat_v(FILE *, const u_char *, int); int install_ttyios(int, const struct termios *); void prepare_term(struct termios *, cc_t); int tty_nonblock(int, int); void *safe_malloc(size_t); void *safe_calloc(size_t, size_t); void *safe_realloc(void *, size_t); char *safe_strdup(const char *); rtty-4.0/README0000644000175000017500000002434310024061624014370 0ustar noodlesnoodles00000000000000rtty -- multiuser "tip"/"cu" replacement with logging Paul Vixie -- 24-March-2001 [V4.0 released] Paul Vixie -- 27-December-1993 [V3.0 released] Paul Vixie -- 1-January-1992 [V2.0 released] $Id: README,v 1.9 2001/03/24 22:33:55 vixie Exp $ 4.0 Release Notes (24-March-2001) Portability to POSIX/ANSI systems (pre-ANSI or pre-POSIX no longer supported.) Uses nonblocking I/O to terminals rather than depending on undependablt VMIN=0. Massive delinting (now passes "gcc -Wall".) 3.3 Release Notes (22-August-1997) Portability to BSD/OS 3.0, bug fixes, better logging. 3.2 Release Notes (23-August-1996) Portability, bug fixes, and a few miscellaneous features like DESTPATH/other/*. 3.0 Release Notes (27-Devember-1993) I've ported it to BSD/386. This led me to make some major changes to the way system routines were declared; the result also works fine on Ultrix 4.2 and should work OK on any modern system, especially POSIX 1003.1 compatible systems. I cleaned up the IP/TCP transport in case anyone wants to try it; in particular there is now a challenge/response for passwords (this used to be "wide open" which is why I always discouraged its use before.) There are some things on my to-do list that I'd like someone else to work on: -> public/private challenge/response, or kerberos, or both -> man pages 2.5 Release Notes (12-Nov-92) This fixes a few minor lint-y things and puts a version stamp in all the binaries. 2.4 Release Notes This version includes the ~query command and online notifications of coming and going. ~tail finally works. 2.1 Release Notes Andrew Partan helped me understand that my termios code was nonportable, and suggested fixes for that and several other embarrassing errors of mine. Meanwhile, back at the ranch, I finally found the right dance to make this thing efficient enough to stop losing characters at 9600 baud, even when multiple clients connect to multiple servers, all with log files running, all on a 3 VUP console server. Introduction Rtty is "remote tty" (not radioteletype). You run a server per port and then connect to that server from any number of "tip"/"cu"-like clients. I wrote it for our console concentrator, but there's no reason other than performance why you couldn't use it to drive modems, printers, prom programmers, and so on. When you connect to the server from more than one client, all clients will see the same session and all clients can type at and see output from whatever device is attached to the tty port. Typing at a device when someone else is also typing at that device is confusing and more than a little bit erie. You will need a BSD-derived UNIX to use this, and you will need "termios" (the POSIX terminal interface). (If "man termios" doesn't say something informative and useful, you are probably hosed.) Ultrix and SunOS and AT&T V.4 all have what you need. AT&T V.3 and non-Tahoe/Reno BSD are both lacking one thing or another. Details The server can be told to keep a log file. This log file will record all data in or out of the tty port; that is, data that comes from the tty port will be logged, and data that is typed at (and therefore sent to) the tty port from any client will be logged. There are no special markers in the log file to tell you which data came from which source; the data is all just interleaved in the order it was received by the server. Note that line terminators in the log file will be "physical" meaning probably \r\n rather than the normal UNIX \n. It depends on the device on the other end of the tty port, but \r\n is pretty common. We watch our log files with daemons that do roughly what "tail -f" does except they scan for things like "file table full" or "out of inodes" or "panic" -- you know, things that computers say when they are unhappy. None of our scanning software is included in this release of rtty, but you can write your own. Note that the protocol used between the server and client is mostly implemented in a separate module of this source directory; if you want to connect to the server in real time and scan the output direcly instead of tailing the log file, that's an option. (You would most especially want to do it this way if you aren't using any log files.) UNIX-domain sockets are the normal way that clients connect to the server. Both client and server support internet-domain sockets (we'll let you figure out "how" by reading the sources), there is absolutely no security in rtty, and opening up our tty ports to the local internet with no access control has seemed like a bad idea (especially since they are the main consoles of our Internet gateway computers). So we don't use this feature. (Win promised to Kerberize this stuff for me but then he got busy.) Futures We need to write some man pages. An RFC for the protocol would be nice. Kerberos or at least a "Password:" prompter/checker would make the internet domain sockets usable, but rsh/xterm presently work so well that ambition is getting its butt kicked by apathy. All that said, this may well be the last version of rtty ever released unless someone else contributes bug fixes or enhancements. Installation These installation instructions assume that you are creating a console server. If you are using this code for something else, you should read all this with several thousand grains of salt. We put everything in /rtty since it is extremely small and most of what gets put there is symlinks and short config files. You will probably put it in /usr/local/rtty or /usr/local/adm/rtty or /usr/local/lib/rtty. Once you decide where you want this stuff, edit the Makefile and change DESTPATH. (Probably you should not change DESTROOT; it's a knob for "make install" when the compilation host and the execution host have different paths to the tree.) Assuming that you put it in /rtty, you will need the following subdirectories: /rtty/bin will contain the server, client, and some shell scripts to glue it all together and make it work. "make install" will populate it but you will need to create the directory first. /rtty/dev will contain symlinks to entries in /dev. the names of the symlinks should be meaningful, and the names in /dev probably will not be meaningful. you might use ln -s /dev/tty15 /rtty/dev/gatekeeper and so on. /rtty/log will contain the log files, if you use them. just create it, the servers will populate it. note that the default behaviour of the "startsrv" script is to use them, so complaints will be issued if you do not create this directory. /rtty/pid will contain server pid's, which are used by the various shell scripts that kill or restart the servers or age the log files. just create it and the servers will populate it. /rtty/sock will contain the UNIX-domain sockets for the various servers. just create it and the servers will populate it. /rtty/opt this directory is optional. if you created it and put in it files of the form $HOST.srv and/or $HOST.cons, then when the server (or "console" client) for that HOST is started, it will use the command line options from this file. the scripts will look for DEFAULT.srv (and DEFAULT.cons) if there is no host-specific option file. if there are no option files at all (or no /rtty/opt directory), the compiled-in defaults are used (baud=9600, parity=none, wordsize=8). example 1: our 11/785 has a 1200-baud console, so... % cat > /rtty/opt/wrlvms.srv -b 1200 ^D example 2: our uVax2 running BSD likes different things in the >>> mode than when /vmunix is running, so... % cat > /rtty/opt/beast.cons -7 ^D /rtty/owner this directory is optional. if you created it and put in it files of the form $HOST.sock, then when the server for that HOST is started, the socket will be chown'd to the contents of this file. typical use is to assign group ownership (by making the file contain root.some-group) to control access to consoles by membership in a particular group. So OK, you've chosen a DESTPATH, created and populated it, and edited the Makefile. Type "make" and if all goes well, type "make install" and "make clean". Make sure you've got /rtty/dev full of all the relevant symlinks into /dev before you continue. Edit root's crontab to include a line like this one: 10 4 * * * sh /rtty/bin/agelogs Edit rc.local or rc.localhost or whatever to include a line like this one: /rtty/bin/Startup Then run that command by hand or reboot your computer. Make a symlink from some common executables directory so that the "console" command is in most people's $PATH. We did this: ln -s /rtty/bin/console /usr/local/bin/console That's all. Type "rehash" and type "console". You should get a list of the available consoles. Pick one (say, "gatekeeper" if you have one) and try something like "console gatekeeper". If it works, bring up another window and do it again. You should see the same session in both windows. Bring up yet another window and say something like "tail -f /rtty/log/gatekeeper". You should see the session in that window, too. Other Notes Since there's no documentation, there's no harm in telling you that the "console" script just runs "rtty" with some obscure arguments to grease its skids. While in "rtty", a "~" after a carriage return (\r or 0x0D) is magic; "~?" will explain the magic to you somewhat tersely. The source code will explain it in more detail. Have fun. Drop me a note if you find this useful. Definitely drop me a note if you find a bug or add a feature. Paul Vixie /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ rtty-4.0/rtty.c0000644000175000017500000003133210024061624014652 0ustar noodlesnoodles00000000000000/* rtty - client of ttysrv * vix 28may91 [written] */ #ifndef LINT static char RCSid[] = "$Id: rtty.c,v 1.16 2001/03/24 21:14:28 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtty.h" #include "misc.h" #include "ttyprot.h" #ifdef WANT_TCPIP # include "locbrok.h" #endif #define LOCAL_DEBUG 0 #define USAGE_STR \ "[-s ServSpec] [-l LoginName] [-7] [-r] [-x DebugLevel] Serv" #define Tty STDIN_FILENO ttyprot T; extern int rconnect(char *host, char *service, FILE *verbose, FILE *errors, int timeout); extern char Version[]; static char *ProgName = "amnesia", WhoAmI[TP_MAXVAR], *ServSpec = NULL, *Login = NULL, *TtyName = NULL, LogSpec[MAXPATHLEN]; static int Serv = -1, Log = -1, Ttyios_set = 0, SevenBit = 0, Restricted = 0, highest_fd = -1; static struct termios Ttyios, Ttyios_orig; static fd_set fds; static void main_loop(void), tty_input(int), query_or_set(int, int), logging(int), serv_input(int), server_replied(char *, int), server_died(void), quit(int); #ifdef DEBUG int Debug = 0; #endif int main(int argc, char *argv[]) { char ch; ProgName = argv[0]; if (!(Login = getlogin())) { struct passwd *pw = getpwuid(getuid()); if (pw) { Login = pw->pw_name; } else { Login = "nobody"; } } if (!(TtyName = ttyname(STDIN_FILENO))) { TtyName = "/dev/null"; } while ((ch = getopt(argc, argv, "s:x:l:7r")) != EOF) { switch (ch) { case 's': ServSpec = optarg; break; #ifdef DEBUG case 'x': Debug = atoi(optarg); break; #endif case 'l': Login = optarg; break; case 'r': Restricted++; break; case '7': SevenBit++; break; default: USAGE((stderr, "%s: getopt=%c ?\n", ProgName, ch)); } } if (optind != argc-1) { USAGE((stderr, "must specify service\n")); } ServSpec = argv[optind++]; sprintf(WhoAmI, "%s@%s", Login, TtyName); if (ServSpec[0] == '/') { struct sockaddr_un n; Serv = socket(PF_UNIX, SOCK_STREAM, 0); ASSERT(Serv>=0, "socket"); n.sun_family = AF_UNIX; (void) strcpy(n.sun_path, ServSpec); ASSERT(0<=connect(Serv, (struct sockaddr *)&n, sizeof n), n.sun_path); dprintf(stderr, "rtty.main: connected on fd%d\r\n", Serv); fprintf(stderr, "connected\n"); } else { #ifdef WANT_TCPIP int loc, len; locbrok lb; char buf[10]; char *cp = strchr(ServSpec, '@'); if (cp) *cp++ = '\0'; else cp = "127.0.0.1"; if ((loc = rconnect(cp, "locbrok", NULL,stderr,30)) == -1) { fprintf(stderr, "can't contact location broker\n"); quit(0); } lb.lb_port = htons(0); len = min(LB_MAXNAMELEN, strlen(ServSpec)); lb.lb_nlen = htons(len); strncpy(lb.lb_name, ServSpec, len); ASSERT(write(loc, &lb, sizeof lb)==sizeof lb, "write lb"); ASSERT(read(loc, &lb, sizeof lb)==sizeof lb, "read lb"); close(loc); lb.lb_port = ntohs(lb.lb_port); dprintf(stderr, "(locbrok: port %d)\n", lb.lb_port); if (!lb.lb_port) { fprintf(stderr, "location broker can't find %s@%s\n", ServSpec, cp); quit(0); } sprintf(buf, "%d", lb.lb_port); Serv = rconnect(cp, buf, NULL,stderr,30); ASSERT(Serv >= 0, "rconnect rtty"); #else USAGE((stderr, "service must begin with a '/'\n")); #endif /*WANT_TCPIP*/ } tcgetattr(Tty, &Ttyios); Ttyios_orig = Ttyios; prepare_term(&Ttyios, 1); signal(SIGINT, quit); signal(SIGQUIT, quit); install_ttyios(Tty, &Ttyios); Ttyios_set++; fprintf(stderr, "(use (CR)~? for minimal help; also (CR)~q? and (CR)~s?)\r\n"); tp_sendctl(Serv, TP_WHOSON, strlen(WhoAmI), (u_char*)WhoAmI); main_loop(); exit(0); } static void main_loop(void) { FD_ZERO(&fds); FD_SET(Serv, &fds); FD_SET(STDIN_FILENO, &fds); highest_fd = max(Serv, STDIN_FILENO); for (;;) { fd_set readfds, exceptfds; int nfound, fd; readfds = fds; exceptfds = fds; nfound = select(highest_fd+1, &readfds, NULL, &exceptfds, NULL); if (nfound < 0 && errno == EINTR) continue; ASSERT(0<=nfound, "select"); for (fd = 0; fd <= highest_fd; fd++) { if (FD_ISSET(fd, &exceptfds)) { if (fd == Serv) server_died(); } if (FD_ISSET(fd, &readfds)) { if (fd == STDIN_FILENO) tty_input(fd); else if (fd == Serv) serv_input(fd); } } } /*NOTREACHED*/ } static void tty_input(int fd) { static enum {base, need_cr, tilde} state = base; u_char buf[1]; int n, save_nonblock; save_nonblock = tty_nonblock(fd, 1); while ((n = read(fd, buf, 1)) == 1) { u_char ch = buf[0]; switch (state) { case base: if (ch == '~') { state = tilde; continue; } if (ch != '\r') { state = need_cr; } break; case need_cr: /* \04 (^D) is a line terminator on some systems */ if (ch == '\r' || ch == '\04') { state = base; } break; case tilde: #define RESTRICTED_HELP_STR "\r\n\ ~^Z - suspend program\r\n\ ~^L - set logging\r\n\ ~q - query server\r\n\ ~s - set option\r\n\ " #define UNRESTRICTED_HELP_STR "\r\n\ ~~ - send one tilde (~)\r\n\ ~. - exit program\r\n\ ~# - send BREAK\r\n\ ~? - this message\r\n\ " state = base; switch (ch) { case '~': /* ~~ - write one ~, which is in buf[] */ break; case '.': /* ~. - quitsville */ (void) tty_nonblock(fd, 0); quit(0); /* FALLTHROUGH */ case 'L'-'@': /* ~^L - start logging */ if (Restricted) goto passthrough; install_ttyios(fd, &Ttyios_orig); logging(fd); install_ttyios(fd, &Ttyios); continue; case 'Z'-'@': /* ~^Z - suspend yourself */ if (Restricted) goto passthrough; install_ttyios(fd, &Ttyios_orig); kill(getpid(), SIGTSTP); install_ttyios(fd, &Ttyios); continue; case 'q': /* ~q - query server */ /*FALLTHROUGH*/ case 's': /* ~s - set option */ if (Restricted) goto passthrough; query_or_set(fd, ch); continue; case '#': /* ~# - send break */ tp_sendctl(Serv, TP_BREAK, 0, NULL); continue; case '?': /* ~? - help */ if (!Restricted) fprintf(stderr, RESTRICTED_HELP_STR); fprintf(stderr, UNRESTRICTED_HELP_STR); continue; passthrough: default: /* ~mumble - write; `mumble' is in buf[] */ tp_senddata(Serv, (u_char *)"~", 1, TP_DATA); if (Log != -1) { write(Log, "~", 1); } break; } break; } if (0 > tp_senddata(Serv, buf, 1, TP_DATA)) { server_died(); } if (Log != -1) { write(Log, buf, 1); } } (void) tty_nonblock(fd, save_nonblock); if (n == 0) quit(0); } static void query_or_set(int fd, int ch) { int set, new, save_nonblock; char buf[64]; switch (ch) { case 'q': set = 0; break; case 's': set = 1; break; default: fputc('G'-'@', stderr); return; } fputs(set ?"~set " :"~query ", stderr); save_nonblock = tty_nonblock(fd, 0); switch (read(fd, buf, 1)) { case -1: perror("read"); goto done; case 0: fprintf(stderr, "!read"); fflush(stderr); goto done; default: break; } switch (buf[0]) { case '\n': case '\r': case 'a': fputs("(show all)\r\n", stderr); tp_sendctl(Serv, TP_BAUD|TP_QUERY, 0, NULL); tp_sendctl(Serv, TP_PARITY|TP_QUERY, 0, NULL); tp_sendctl(Serv, TP_WORDSIZE|TP_QUERY, 0, NULL); break; case 'b': if (!set) { fputs("\07\r\n", stderr); } else { fputs("baud ", stderr); install_ttyios(fd, &Ttyios_orig); fgets(buf, sizeof buf, stdin); if (buf[strlen(buf)-1] == '\n') { buf[strlen(buf)-1] = '\0'; } if (!(new = atoi(buf))) { break; } tp_sendctl(Serv, TP_BAUD, new, NULL); } break; case 'p': if (!set) { fputs("\07\r\n", stderr); } else { fputs("parity ", stderr); install_ttyios(fd, &Ttyios_orig); fgets(buf, sizeof buf, stdin); if (buf[strlen(buf)-1] == '\n') { buf[strlen(buf)-1] = '\0'; } tp_sendctl(Serv, TP_PARITY, strlen(buf), (u_char *)buf); } break; case 'w': if (!set) { fputs("\07\r\n", stderr); } else { fputs("wordsize ", stderr); install_ttyios(fd, &Ttyios_orig); fgets(buf, sizeof buf, stdin); if (!(new = atoi(buf))) { break; } tp_sendctl(Serv, TP_WORDSIZE, new, NULL); } break; case 'T': if (set) { fputs("\07\r\n", stderr); } else { fputs("Tail\r\n", stderr); tp_sendctl(Serv, TP_TAIL|TP_QUERY, 0, NULL); } break; case 'W': if (set) { fputs("\07\r\n", stderr); } else { fputs("Whoson\r\n", stderr); tp_sendctl(Serv, TP_WHOSON|TP_QUERY, 0, NULL); } break; case 'V': if (set) { fputs("\07\r\n", stderr); } else { fputs("Version\r\n", stderr); tp_sendctl(Serv, TP_VERSION|TP_QUERY, 0, NULL); fprintf(stderr, "[%s (client)]\r\n", Version); } break; default: if (set) fputs("[all baud parity wordsize]\r\n", stderr); else fputs("[all Whoson Tail Version]\r\n", stderr); break; } done: (void) tty_nonblock(fd, save_nonblock); return; } static void logging(int fd) { if (Log == -1) { int save_nonblock = tty_nonblock(fd, 0); printf("\r\nLog file is: "); fflush(stdout); fgets(LogSpec, sizeof LogSpec, stdin); if (LogSpec[strlen(LogSpec) - 1] == '\n') LogSpec[strlen(LogSpec)-1] = '\0'; if (LogSpec[0]) { Log = open(LogSpec, O_CREAT|O_APPEND|O_WRONLY, 0640); if (Log == -1) perror(LogSpec); } (void) tty_nonblock(fd, save_nonblock); } else { if (0 > close(Log)) perror(LogSpec); else printf("\n[%s closed]\n", LogSpec); Log = -1; } } static void serv_input(int fd) { char passwd[TP_MAXVAR], s[3], *c, *crypt(); int nchars, i; u_int f, o, t; if (0 >= (nchars = read(fd, &T, TP_FIXED))) { fprintf(stderr, "serv_input: read(%d) returns %d\n", fd, nchars); server_died(); } i = ntohs(T.i); f = ntohs(T.f); o = f & TP_OPTIONMASK; t = f & TP_TYPEMASK; switch (t) { case TP_DATA: /* FALLTHROUGH */ case TP_NOTICE: if (i != (nchars = read(fd, T.c, i))) { fprintf(stderr, "serv_input: read@%d need %d got %d\n", fd, i, nchars); server_died(); } if (SevenBit) { int i; for (i = 0; i < nchars; i++) T.c[i] &= 0x7f; } switch (t) { case TP_DATA: write(STDOUT_FILENO, T.c, nchars); if (Log != -1) write(Log, T.c, nchars); break; case TP_NOTICE: write(STDOUT_FILENO, "[", 1); write(STDOUT_FILENO, T.c, nchars); write(STDOUT_FILENO, "]\r\n", 3); if (Log != -1) { write(Log, "[", 1); write(Log, T.c, nchars); write(Log, "]\r\n", 3); } break; default: break; } break; case TP_BAUD: if ((o & TP_QUERY) != 0) fprintf(stderr, "[baud %d]\r\n", i); else server_replied("baud rate change", i); break; case TP_PARITY: if ((o & TP_QUERY) != 0) { if (i != (nchars = read(fd, T.c, i))) { server_died(); } T.c[i] = '\0'; fprintf(stderr, "[parity %s]\r\n", T.c); } else { server_replied("parity change", i); } break; case TP_WORDSIZE: if ((o & TP_QUERY) != 0) fprintf(stderr, "[wordsize %d]\r\n", i); else server_replied("wordsize change", i); break; case TP_LOGIN: if ((o & TP_QUERY) == 0) break; tp_sendctl(Serv, TP_LOGIN, strlen(Login), (u_char*)Login); break; case TP_PASSWD: if ((o & TP_QUERY) == 0) break; fputs("Password:", stderr); fflush(stderr); for (c = passwd; c < &passwd[sizeof passwd]; c++) { fd_set infd; FD_ZERO(&infd); FD_SET(Tty, &infd); if (1 != select(Tty+1, &infd, NULL, NULL, NULL)) break; if (1 != read(Tty, c, 1)) break; if (*c == '\r') break; } *c = '\0'; fputs("\r\n", stderr); fflush(stderr); s[0] = 0xff & (i>>8); s[1] = 0xff & i; s[2] = '\0'; c = crypt(passwd, s); tp_sendctl(Serv, TP_PASSWD, strlen(c), (u_char*)c); break; } } static void server_replied(char *msg, int i) { fprintf(stderr, "[%s %s]\r\n", msg, i ? "accepted" : "rejected"); } static void server_died(void) { fprintf(stderr, "\r\n[server disconnect]\r\n"); quit(0); } static void quit(int x) { fprintf(stderr, "\r\n[rtty exiting]\r\n"); if (Ttyios_set) install_ttyios(Tty, &Ttyios_orig); exit(0); } rtty-4.0/rtty.h0000644000175000017500000000311610024061624014656 0ustar noodlesnoodles00000000000000/* rtty.h - definitions for rtty package * vix 01nov91 [written] * * $Id: rtty.h,v 1.10 2001/03/24 21:14:29 vixie Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #define ASSERT2(e, m1, m2) if (!(e)) {int save_errno=errno;\ fprintf(stderr, "%s: %s: ",\ ProgName, m2);\ errno=save_errno;\ perror(m1); exit(1);} #define ASSERT(e, m) ASSERT2(e, m, "") #define USAGE(x) { fprintf x;\ fprintf(stderr, "usage: %s %s\n",\ ProgName, USAGE_STR);\ exit(1); } #define TRUE 1 #define FALSE 0 #define min(a,b) ((a>b)?b:a) #define max(a,b) ((a>b)?a:b) #ifndef dprintf # ifdef DEBUG # define dprintf if (Debug) fprintf # else # define dprintf (void) # endif #endif /* something in ULTRIX that we want to use if it's there */ #ifndef TAUTOFLOW #define TAUTOFLOW 0 #endif rtty-4.0/startsrv.sh0000644000175000017500000000551610024061624015735 0ustar noodlesnoodles00000000000000#!/bin/sh # $Id: startsrv.sh,v 1.10 2001/03/24 21:17:40 vixie Exp $ # Copyright (c) 1996 by Internet Software Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS # ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE # CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. default_options='-b 9600 -w 8 -p none' default_sock_prot='ug=rw,o=' default_sock_owner='root.wheel' default_log_prot='u=rw,g=r,o=' for host do echo -n "startsrv($host):" # # kill any existing ttysrv on this port # if [ -f DESTPATH/pid/$host ]; then pid=`cat DESTPATH/pid/$host` while ps w$pid >/tmp/startsrv$$ 2>&1 do grep -q ttysrv /tmp/startsrv$$ && { echo -n " $pid killed" kill $pid sleep 1 } || { break } done rm DESTPATH/pid/$host /tmp/startsrv$$ fi # # start up a new one # if [ -s DESTPATH/opt/${host}.srv ]; then options=`cat DESTPATH/opt/${host}.srv` elif [ -s DESTPATH/opt/DEFAULT.srv ]; then options=`cat DESTPATH/opt/DEFAULT.srv` else options="$default_options" fi if [ -s DESTPATH/prot/${host}.sock ]; then sock_prot=`cat DESTPATH/prot/${host}.sock` elif [ -s DESTPATH/prot/DEFAULT.sock ]; then sock_prot=`cat DESTPATH/prot/DEFAULT.sock` else sock_prot="$default_sock_prot" fi if [ -s DESTPATH/owner/${host}.sock ]; then sock_owner=`cat DESTPATH/owner/${host}.sock` elif [ -s DESTPATH/owner/DEFAULT.sock ]; then sock_owner=`cat DESTPATH/owner/DEFAULT.sock` else sock_owner="$default_sock_owner" fi if [ -s DESTPATH/prot/${host}.log ]; then log_prot=`cat DESTPATH/prot/${host}.log` elif [ -s DESTPATH/prot/DEFAULT.log ]; then log_prot=`cat DESTPATH/prot/DEFAULT.log` else log_prot="$default_log_prot" fi rm -f DESTPATH/sock/$host DESTPATH/pid/$host DESTPATH/bin/ttysrv $options \ -t DESTPATH/dev/$host \ -s DESTPATH/sock/$host \ -l DESTPATH/log/$host \ -i DESTPATH/pid/$host \ > DESTPATH/out/$host 2>&1 & echo -n " " tries=5 while [ $tries -gt 0 -a ! -f DESTPATH/pid/$host ]; do echo -n "." sleep 1 tries=`expr $tries - 1` done if [ ! -f DESTPATH/pid/$host ]; then echo " [startup failed]" else newpid=`cat DESTPATH/pid/$host` chmod $sock_prot DESTPATH/sock/$host chown $sock_owner DESTPATH/sock/$host chmod $log_prot DESTPATH/log/$host echo " $newpid started" fi done exit rtty-4.0/Startup.sh0000644000175000017500000000165310024061624015505 0ustar noodlesnoodles00000000000000#!/bin/sh # $Id: Startup.sh,v 1.4 1997/08/22 20:11:54 vixie Exp $ # Copyright (c) 1996 by Internet Software Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS # ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE # CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. cd DESTPATH rm -f pid/* cd dev DESTPATH/bin/startsrv * exit rtty-4.0/ttyprot.c0000644000175000017500000000561510024061624015402 0ustar noodlesnoodles00000000000000/* ttyprot.c - utility routines to deal with the rtty protocol * vixie 12Sep91 [new] */ #ifndef LINT static char RCSid[] = "$Id: ttyprot.c,v 1.10 2001/03/24 21:14:30 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include #include #include #include #include "rtty.h" #include "misc.h" #include "ttyprot.h" #if DEBUG extern int Debug; #endif int tp_senddata(int fd, const u_char *buf, int len, int typ) { struct iovec iov[2]; ttyprot t; int n = 0; #if DEBUG if (Debug >= 5) { fprintf(stderr, "tp_senddata(fd=%d, buf=\"", fd); cat_v(stderr, buf, len); fprintf(stderr, "\", len=%d, typ=%d)\r\n", len, typ); } #endif t.f = htons(typ); iov[0].iov_base = (caddr_t)&t; iov[0].iov_len = TP_FIXED; while (len > 0) { int i = min(len, TP_MAXVAR); t.i = htons(i); iov[1].iov_base = (caddr_t)buf; iov[1].iov_len = i; buf += i; len -= i; i = writev(fd, iov, 2); if (i < 0) break; n += i; } return (n); } int tp_sendctl(int fd, u_int f, u_int i, u_char *c) { struct iovec iov[2]; ttyprot t; int len = c ?min(strlen((char *)c), TP_MAXVAR) :0; int il = 0; #if DEBUG if (Debug >= 5) { fprintf(stderr, "tp_sendctl(fd=%d, f=%04x, i=%d, c=\"", fd, f, i); cat_v(stderr, c ?c :(u_char*)"", len); fprintf(stderr, "\")\r\n"); } #endif t.f = htons(f); t.i = htons(i); iov[il].iov_base = (caddr_t)&t; iov[il].iov_len = TP_FIXED; il++; if (c) { iov[il].iov_base = (caddr_t)c; iov[il].iov_len = len; il++; } return (writev(fd, iov, il)); } int tp_getdata(int fd, ttyprot *tp) { int len = ntohs(tp->i); int nchars; if ((nchars = read(fd, tp->c, len)) != len) { dprintf(stderr, "tp_getdata: read=%d(%d) fd%d: ", nchars, len, fd); if (nchars < 0) perror("read#2"); else fputc('\n', stderr); return (0); } #ifdef DEBUG if (Debug >= 5) { fprintf(stderr, "tp_getdata(fd%d, len%d): got %d bytes", fd, len, nchars); if (Debug >= 6) { fputs(": \"", stderr); cat_v(stderr, tp->c, nchars); fputs("\"", stderr); } fputc('\n', stderr); } #endif return (nchars); } rtty-4.0/ttyprot.h0000644000175000017500000000375210024061624015407 0ustar noodlesnoodles00000000000000/* ttyproto.h - define protocol used by ttysrv and its clients * vix 29may91 [written] * * $Id: ttyprot.h,v 1.9 2001/03/24 21:14:31 vixie Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #ifdef NEED_BITYPES_H # include "bitypes.h" #endif #define TP_TYPEMASK 0x00ff #define TP_DATA 0x0001 /* inband data (query=ignored) */ #define TP_BAUD 0x0002 #define TP_PARITY 0x0003 #define TP_WORDSIZE 0x0004 #define TP_BREAK 0x0005 /* send break (query=ignored) */ #define TP_WHOSON 0x0006 /* who's connected to this tty? (set=="me") */ #define TP_TAIL 0x0007 /* what's happened recently? (set==ignored) */ #define TP_NOTICE 0x0008 /* same as DATA but generated by server */ #define TP_VERSION 0x0009 /* what's your version number? (set==ignore) */ #define TP_LOGIN 0x000a #define TP_PASSWD 0x000b /* query's "i" field is the salt (netorder) */ #define TP_OPTIONMASK 0xff00 #define TP_QUERY 0x0100 #define TP_FIXED (sizeof(u_int16_t) + sizeof(u_int16_t)) #define TP_MAXVAR 468 /* 512 - 40 - TP_FIXED */ typedef struct ttyprot { u_int16_t f; u_int16_t i; u_char c[TP_MAXVAR]; } ttyprot; int tp_senddata(int, const u_char *, int, int); int tp_sendctl(int, u_int, u_int, u_char *); int tp_getdata(int, ttyprot *); rtty-4.0/ttysrv.c0000644000175000017500000004670210024061624015232 0ustar noodlesnoodles00000000000000/* ttysrv - serve a tty to stdin/stdout, a named pipe, or a network socket * vix 28may91 [written] */ #ifndef LINT static char RCSid[] = "$Id: ttysrv.c,v 1.17 2001/03/24 21:14:32 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(DEBUG) && !defined(dprintf) #define dprintf if (Debug) lprintf #else #define dprintf (void) #endif #include "rtty.h" #include "misc.h" #include "ttyprot.h" #ifdef WANT_TCPIP # include "locbrok.h" #endif struct whoson { char *who, *host, *auth; time_t lastInput; enum {local, remote} type; enum {wlogin, wpasswd, auth} state; int aux; }; #define MAX_AUTH_ATTEMPTS 3 #define USAGE_STR "{-o option} [-s LServ|-r RServ] [-l Log]\n\ -t Tty [-b Baud] [-p Parity] [-w Wordsize] [-i Pidfile]" #ifdef DEBUG int Debug = 0; #endif extern int rconnect(char *host, char *service, FILE *verbose, FILE *errors, int timeout); extern char Version[]; static char *ProgName = "amnesia", *LServSpec = NULL, *RServSpec = NULL, *TtySpec = NULL, *LogSpec = NULL, *Parity = "none", ParityBuf[TP_MAXVAR], *PidFile = NULL; static int LServ = -1, RServ = -1, Tty = -1, Ttyios_set = 0, LogDirty = FALSE, Baud = 9600, Wordsize = 8, highest_fd = -1, #ifdef WANT_TCPIP LocBrok = -1, #endif Sigpiped = 0; #ifdef WANT_TCPIP static u_int Port; #endif static struct termios Ttyios, Ttyios_orig; static FILE *LogF = NULL; static fd_set Clients; static ttyprot T; static time_t Now; static char Hostname[MAXHOSTNAMELEN]; static struct timeval TOinput = {0, 3000}; /* 3ms: >1byte @9600baud */ static struct timeval TOflush = {1, 0}; /* 1 second */ static struct whoson **WhosOn; static char *handle_option(char *); static void main_loop(void), tty_input(int, int), broadcast(u_char *, int, u_int), sigpipe(int), sighup(int), open_log(void), quit(int), serv_input(int), client_input(int), close_client(int), set_parity(u_int), set_wordsize(u_int), auth_needed(int), auth_ok(int), lprintf(FILE *, const char *, ...); static int set_baud(int), find_parity(char *), find_wordsize(int); int main(int argc, char *argv[]) { int i; char ch, *msg; gethostname(Hostname, sizeof Hostname); ProgName = argv[0]; while ((ch = getopt(argc, argv, "o:s:r:t:l:b:p:w:x:i:")) != EOF) { switch (ch) { case 'o': msg = handle_option(optarg); if (msg) { USAGE((stderr, "%s: bad option (%s): %s\n", ProgName, optarg, msg)); } case 's': LServSpec = optarg; break; case 'r': #ifdef WANT_TCPIP RServSpec = optarg; #else USAGE((stderr, "%s: -r not supported on this system\n", ProgName)); #endif break; case 't': TtySpec = optarg; break; case 'l': LogSpec = optarg; break; case 'b': Baud = atoi(optarg); break; case 'p': Parity = optarg; break; case 'w': Wordsize = atoi(optarg); break; #ifdef DEBUG case 'x': Debug = atoi(optarg); break; #endif case 'i': PidFile = optarg; break; default: USAGE((stderr, "%s: getopt=%c ?\n", ProgName, ch)); } } if (!TtySpec) { USAGE((stderr, "%s: must specify -t ttyspec ?\n", ProgName)); } if (0 > (Tty = open(TtySpec, O_NONBLOCK|O_RDWR))) { fprintf(stderr, "%s: can't open tty ", ProgName); perror(TtySpec); exit(2); } dprintf(stderr, "main: tty open on fd%d\n", Tty); tcgetattr(Tty, &Ttyios); Ttyios_orig = Ttyios; prepare_term(&Ttyios, 0); set_baud(Baud); if ((i = find_parity(Parity)) == -1) { USAGE((stderr, "%s: parity %s ?\n", ProgName, Parity)); } set_parity(i); if ((i = find_wordsize(Wordsize)) == -1) { USAGE((stderr, "%s: wordsize %d ?\n", ProgName, Wordsize)); } set_wordsize(i); signal(SIGINT, quit); signal(SIGQUIT, quit); install_ttyios(Tty, &Ttyios); Ttyios_set++; if (!LServSpec && !RServSpec) { USAGE((stderr, "%s: must specify either -s or -r\n", ProgName)); } if (LServSpec) { struct sockaddr_un n; struct stat statbuf; if (LServSpec[0] != '/') { USAGE((stderr, "%s: -s must specify local pathname\n", ProgName)); } LServ = socket(PF_UNIX, SOCK_STREAM, 0); ASSERT(LServ>=0, "socket"); n.sun_family = AF_UNIX; (void) strcpy(n.sun_path, LServSpec); if (stat(LServSpec, &statbuf) >= 0) { fprintf(stderr, "warning: removing \"%s\"\n", LServSpec); if ((statbuf.st_mode & S_IFMT) == S_IFSOCK) { if (unlink(LServSpec) < 0) perror("unlink"); } } ASSERT(0<=bind(LServ, (struct sockaddr *)&n, sizeof n), n.sun_path); } #ifdef WANT_TCPIP if (RServSpec) { struct sockaddr_in n; int nlen = sizeof n; RServ = socket(PF_INET, SOCK_STREAM, 0); ASSERT(RServ>=0, "socket"); n.sin_family = AF_INET; #ifndef NO_SOCKADDR_LEN n.sin_len = sizeof(struct sockaddr_in); #endif n.sin_port = 0; /* "any" */ n.sin_addr.s_addr = INADDR_ANY; ASSERT(0<=bind(RServ, (struct sockaddr *)&n, sizeof n), "bind"); ASSERT(0<=getsockname(RServ, (struct sockaddr *)&n, &nlen), "getsockname"); Port = ntohs(n.sin_port); fprintf(stderr, "serving internet port %d\n", Port); /* register with the location broker, or die */ { int len = min(LB_MAXNAMELEN, strlen(RServSpec)); locbrok lb; LocBrok = rconnect("127.1", "locbrok", NULL,stderr,0); ASSERT(LocBrok>0, "rconnect locbrok"); lb.lb_port = htons(Port); lb.lb_nlen = htons(len); strncpy(lb.lb_name, RServSpec, len); ASSERT(0 2) lprintf(stderr, "main_loop: select(%d,%08x) LD=%d\n", highest_fd+1, readfds.fds_bits[0], LogDirty); #endif nfound = select(highest_fd+1, &readfds, NULL, NULL, (LogDirty ?&TOflush :NULL)); if (nfound < 0 && errno == EINTR) continue; if (nfound == 0 && LogDirty && LogF) { fflush(LogF); LogDirty = FALSE; } Now = time(0); #ifdef DEBUG if (Debug > 2) lprintf(stderr, "main_loop: select->%d\n", nfound); #endif for (fd = 0; fd <= highest_fd; fd++) { if (!FD_ISSET(fd, &readfds)) { continue; } dprintf(stderr, "main_loop: fd%d readable\n", fd); if (fd == Tty) { tty_input(fd, FALSE); tty_input(fd, TRUE); } else if ((fd == LServ) || (fd == RServ)) { serv_input(fd); } else { client_input(fd); } } } /*NOTREACHED*/ } static void tty_input(int fd, int aggregate) { u_char buf[TP_MAXVAR]; int nchars, x, nloops; nchars = 0; nloops = 0; do { nloops++; x = read(fd, buf+nchars, TP_MAXVAR-nchars); } while ((x > 0) && ((nchars += x) < TP_MAXVAR) && (aggregate && !select(0, NULL, NULL, NULL, &TOinput)) ) ; #ifdef DEBUG if (Debug) { lprintf(stderr, "tty_input: %d bytes read on fd%d (nl %d)", nchars, fd, nloops); if (Debug > 1) { fputs(": \"", stderr); cat_v(stderr, buf, nchars); fputs("\"", stderr); } fputc('\n', stderr); } #endif if (nchars == 0) return; if (LogF) { if (nchars != fwrite(buf, sizeof(char), nchars, LogF)) { perror("fwrite(LogF)"); } else { LogDirty = TRUE; } } broadcast(buf, nchars, TP_DATA); } static void broadcast(u_char *buf, int nchars, u_int typ) { int fd, x; for (fd = 0; fd <= highest_fd; fd++) { if (!FD_ISSET(fd, &Clients)) { continue; } Sigpiped = 0; x = tp_senddata(fd, buf, nchars, typ); dprintf(stderr, "tty_input: %d bytes sent to client on fd%d\n", x, fd); if (Sigpiped) { dprintf(stderr, "tty_input: sigpipe on fd%d\n", fd); close_client(fd); } } } static void serv_input(int fd) { struct sockaddr_un un; struct sockaddr_in in; struct sockaddr *sa; int fromlen; if (fd == LServ) { sa = (struct sockaddr *) &un; fromlen = sizeof(un); } else if (fd == RServ) { sa = (struct sockaddr *) ∈ fromlen = sizeof(in); } else { fprintf(stderr, "%s: panic - serv_input(%d)\n", ProgName, fd); abort(); } dprintf(stderr, "serv_input: accepting on fd%d\n", fd); if ((fd = accept(fd, sa, &fromlen)) == -1) { perror("accept"); return; } dprintf(stderr, "serv_input: accepted fd%d\n", fd); FD_SET(fd, &Clients); if (fd > highest_fd) { highest_fd = fd; } if (!WhosOn[fd]) { WhosOn[fd] = (struct whoson *) malloc(sizeof(struct whoson)); } WhosOn[fd]->who = NULL; WhosOn[fd]->lastInput = Now; WhosOn[fd]->auth = NULL; if (sa == (struct sockaddr *) &un) { WhosOn[fd]->host = safe_strdup(Hostname); WhosOn[fd]->type = local; auth_ok(fd); } else if (sa == (struct sockaddr *) &in) { struct hostent *hp, *gethostbyaddr(); hp = gethostbyaddr((char *)&in.sin_addr, sizeof(in.sin_addr), in.sin_family); WhosOn[fd]->host = safe_strdup(hp ? hp->h_name : inet_ntoa(in.sin_addr)); WhosOn[fd]->type = remote; auth_needed(fd); } else { fprintf(stderr, "%s: panic - serv_input #2\n", ProgName); abort(); } } static void client_input(int fd) { int nchars, i, new, query; struct passwd *pw; u_short salt; char s[3]; u_int f; if (!WhosOn[fd]) return; WhosOn[fd]->lastInput = Now; /* read the fixed part of the ttyprot (everything but the array) */ if (TP_FIXED != (nchars = read(fd, &T, TP_FIXED))) { dprintf(stderr, "client_input: read=%d on fd%d: ", nchars, fd); #ifdef DEBUG if (Debug) perror("read"); #endif close_client(fd); return; } #ifdef DEBUG_not cat_v(stderr, &T, nchars); #endif i = ntohs(T.i); query = ntohs(T.f) & TP_QUERY; f = ntohs(T.f) & TP_TYPEMASK; #ifdef DEBUG if (Debug) { lprintf(stderr, "client_input: nchars=%d fd%d i=0x%x o='%c' f=0x%x\n", nchars, fd, i, query?'Q':' ', f); } #endif switch (f) { case TP_DATA: if (!(nchars = tp_getdata(fd, &T))) { close_client(fd); break; } dprintf(stderr, "client_input: TP_DATA, nchars=%d\n", nchars); if (WhosOn[fd]->state != auth) break; # if WANT_CLIENT_LOGGING if (LogF) { if (nchars != fwrite(T.c, sizeof(char), nchars, LogF)){ perror("fwrite(LogF)"); } else { LogDirty = TRUE; } } # endif /*WANT_CLIENT_LOGGING*/ nchars = write(Tty, T.c, nchars); #ifdef DEBUG if (Debug > 2) { lprintf(stderr, "client_input: wrote to tty: \""); cat_v(stderr, (u_char *)&T.c, nchars); fputs("\"\n", stderr); } #endif break; case TP_BREAK: if (WhosOn[fd]->state != auth) break; dprintf(stderr, "client_input: sending break\n"); tcsendbreak(Tty, 0); tp_senddata(fd, (u_char *)"BREAK", 5, TP_NOTICE); if (LogF) fputs("[BREAK]", LogF); dprintf(stderr, "client_input: done sending break\n"); break; case TP_BAUD: if (WhosOn[fd]->state != auth) break; if (query) { tp_sendctl(fd, TP_BAUD|TP_QUERY, Baud, NULL); break; } if ((set_baud(i) >= 0) && (install_ttyios(Tty, &Ttyios) >= 0)) { Baud = i; if (LogF) fprintf(LogF, "[baud now %d]", i); tp_sendctl(fd, TP_BAUD, 1, NULL); } else { tp_sendctl(fd, TP_BAUD, 0, NULL); } break; case TP_PARITY: if (!query) { if (!(nchars = tp_getdata(fd, &T))) { close_client(fd); break; } T.c[i] = '\0'; /* XXX */ } if (WhosOn[fd]->state != auth) break; if (query) { tp_sendctl(fd, TP_PARITY|TP_QUERY, strlen(Parity), (u_char *)Parity); break; } if (-1 == (new = find_parity((char *)T.c))) { tp_sendctl(fd, TP_PARITY, 0, NULL); } else { strcpy(ParityBuf, (char *)T.c); Parity = ParityBuf; set_parity(new); install_ttyios(Tty, &Ttyios); if (LogF) { fprintf(LogF, "[parity now %s]", (char*) T.c); } tp_sendctl(fd, TP_PARITY, 1, NULL); } break; case TP_WORDSIZE: if (WhosOn[fd]->state != auth) break; if (query) { tp_sendctl(fd, TP_WORDSIZE|TP_QUERY, Wordsize, NULL); break; } if (-1 == (new = find_wordsize(i))) { tp_sendctl(fd, TP_WORDSIZE, 0, NULL); } else { Wordsize = i; set_wordsize(new); install_ttyios(Tty, &Ttyios); if (LogF) { fprintf(LogF, "[wordsize now %d]", i); } tp_sendctl(fd, TP_WORDSIZE, 1, NULL); } break; case TP_WHOSON: if (!query) { if (!(nchars = tp_getdata(fd, &T))) { close_client(fd); break; } T.c[i] = '\0'; /* XXX */ } if (WhosOn[fd]->state != auth) break; if (query) { int iwho; for (iwho = getdtablesize()-1; iwho >= 0; iwho--) { struct whoson *who = WhosOn[iwho]; char data[TP_MAXVAR]; int idle; if (!who) continue; idle = Now - who->lastInput; sprintf(data, "%s [%s] (idle %d sec%s)", who->who ?who->who :"undeclared", who->host ?who->host :"?", idle, (idle==1) ?"" :"s"); tp_senddata(fd, (u_char *)data, strlen(data), TP_NOTICE); } break; } if (WhosOn[fd]) { if (WhosOn[fd]->who) free(WhosOn[fd]->who); WhosOn[fd]->who = safe_strdup((char *)T.c); } { /*local*/ char buf[TP_MAXVAR]; sprintf(buf, "%-*.*s connected\07", i, i, T.c); broadcast((u_char *)buf, strlen(buf), TP_NOTICE); } break; case TP_TAIL: if (WhosOn[fd]->state != auth) break; if (!query) break; if (!LogF) break; fflush(LogF); LogDirty = FALSE; if (ftell(LogF) < 1024L) { if (0 > fseek(LogF, 0, SEEK_SET)) break; } else { if (0 > fseek(LogF, -1024, SEEK_END)) break; } { /*local*/ char buf[TP_MAXVAR]; int len, something = FALSE; while (0 < (len = fread(buf, sizeof(char), sizeof buf, LogF))) { if (!something) { tp_senddata(fd, (u_char*)"tail+", 5, TP_NOTICE); something = TRUE; } tp_senddata(fd, (u_char*)buf, len, TP_DATA); } if (something) { tp_senddata(fd, (u_char*)"tail-", 5, TP_NOTICE); } } break; case TP_VERSION: if (!query) break; tp_senddata(fd, (u_char*)Version, strlen(Version), TP_NOTICE); break; case TP_LOGIN: if (!(nchars = tp_getdata(fd, &T))) { close_client(fd); break; } T.c[i] = '\0'; /* XXX */ if (query) break; if (WhosOn[fd]->state != wlogin) break; pw = getpwnam((char*)T.c); if (!pw) { char data[TP_MAXVAR]; sprintf(data, "%s - no such user", T.c); tp_senddata(fd, (u_char*)data, strlen(data), TP_NOTICE); } else if (!pw->pw_passwd[0]) { auth_ok(fd); } else { WhosOn[fd]->state = wpasswd; WhosOn[fd]->auth = safe_strdup(pw->pw_passwd); salt = WhosOn[fd]->auth[0]<<8 | WhosOn[fd]->auth[1]; tp_sendctl(fd, TP_PASSWD|TP_QUERY, salt, NULL); } break; case TP_PASSWD: if (!(nchars = tp_getdata(fd, &T))) { close_client(fd); break; } T.c[i] = '\0'; /* XXX */ if (query) break; if (WhosOn[fd]->state != wpasswd) break; strncpy(s, WhosOn[fd]->auth, 2); if (!strcmp((char*)T.c, WhosOn[fd]->auth)) { auth_ok(fd); } else { char data[TP_MAXVAR]; sprintf(data, "login incorrect"); if (++WhosOn[fd]->aux > MAX_AUTH_ATTEMPTS) { close_client(fd); } else { tp_senddata(fd, (u_char*)data, strlen(data), TP_NOTICE); auth_needed(fd); } } break; default: dprintf(stderr, "client_input: bad T: f=0x%x\n", ntohs(T.f)); break; } } static void close_client(int fd) { dprintf(stderr, "close_client: fd%d\n", fd); close(fd); FD_CLR(fd, &Clients); if (WhosOn[fd]) { if (WhosOn[fd]->who) { char buf[TP_MAXVAR]; sprintf(buf, "%s disconnected\07", WhosOn[fd]->who); broadcast((u_char*)buf, strlen(buf), TP_NOTICE); free(WhosOn[fd]->who); } free(WhosOn[fd]->host); if (WhosOn[fd]->auth) free(WhosOn[fd]->auth); free((char *) WhosOn[fd]); WhosOn[fd] = (struct whoson *) NULL; } } struct partab { char *parity; int sysparity; } partab[] = { { "even", PARENB }, { "odd", PARENB|PARODD }, { "none", 0 }, { NULL, -1 } }; struct cstab { int wordsize, syswordsize; } cstab[] = { { 5, CS5 }, { 6, CS6 }, { 7, CS7 }, { 8, CS8 }, { 0, -1 } }; static int set_baud(int baud) { if (cfsetispeed(&Ttyios, baud) < 0) return -1; if (cfsetospeed(&Ttyios, baud) < 0) return -1; return (0); } static int find_parity(char *parity) { struct partab *parp; int sysparity = -1; for (parp = partab; parp->parity; parp++) { if (!strcmp(parp->parity, parity)) { sysparity = parp->sysparity; } } return (sysparity); } static void set_parity(u_int parity) { Ttyios.c_cflag &= ~(PARENB|PARODD); Ttyios.c_cflag |= parity; } static int find_wordsize(int wordsize) { struct cstab *csp; int syswordsize = -1; for (csp = cstab; csp->wordsize; csp++) { if (csp->wordsize == wordsize) syswordsize = csp->syswordsize; } return (syswordsize); } static void set_wordsize(u_int wordsize) { Ttyios.c_cflag &= ~CSIZE; Ttyios.c_cflag |= wordsize; } static char * handle_option(char *option) { if (!strcmp("nolocal", option)) { Ttyios.c_cflag &= ~CLOCAL; } else { return "unrecognized"; } return (NULL); } static void auth_needed(int fd) { char data[TP_MAXVAR]; sprintf(data, "authorization needed"); tp_senddata(fd, (u_char*)data, strlen(data), TP_NOTICE); WhosOn[fd]->state = wlogin; tp_sendctl(fd, TP_LOGIN|TP_QUERY, 0, NULL); } static void auth_ok(int fd) { char data[TP_MAXVAR]; sprintf(data, "authorized"); tp_senddata(fd, (u_char*)data, strlen(data), TP_NOTICE); WhosOn[fd]->state = auth; } static void sigpipe(int x) { Sigpiped++; } static void sighup(int x) { if (LogF) { fclose(LogF); LogF = NULL; LogDirty = FALSE; open_log(); } } static void open_log(void) { if (!(LogF = fopen(LogSpec, "a+"))) { perror(LogSpec); fprintf(stderr, "%s: can't open log file\n", ProgName); } } static void quit(int x) { dprintf(stderr, "\r\nttysrv exiting\r\n"); if (Ttyios_set && (Tty != -1)) (void) install_ttyios(Tty, &Ttyios_orig); exit(0); } #ifdef DEBUG static void lprintf(FILE *fp, const char *fmt, ...) { va_list ap; struct timeval tvnow; struct tm *tmnow; time_t now; va_start(ap, fmt); (void) gettimeofday(&tvnow, NULL); now = (time_t) tvnow.tv_sec; tmnow = localtime(&now); fprintf(fp, "%02d:%02d:%02d.%03d ", tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec, (int) (tvnow.tv_usec / 1000)); vfprintf(fp, fmt, ap); va_end(ap); } #endif