[alt.sources] Autobaud getty replacement for System V Machines

karl@ddsw1.MCS.COM (Karl Denninger) (01/21/91)

A program to replace getty on System V machines, this autobauder shares
ports with UUCP and CU easily.  See distribution restrictions below.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  autouu.c
# Wrapped by karl@ddsw1 on Sun Jan 20 13:40:17 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'autouu.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'autouu.c'\"
else
echo shar: Extracting \"'autouu.c'\" \(19854 characters\)
sed "s/^X//" >'autouu.c' <<'END_OF_FILE'
X/*
X *	Copyright 1990 MCS & Karl Denninger.  All rights reserved.
X *
X *	Public use is permitted under the following conditions:
X *
X *	1) You do not remove my name from the package, or claim you wrote it.
X *	2) You distribute ORIGINAL source code with all distributions made,
X *	   modified or not, binary or source.
X *	3) You do not attempt to sell the package, or use it to enhance the
X *	   commercial value of any product or service.  
X *	4) This package is distributed with ABSOLUTELY NO WARRANTY OF ANY
X *	   KIND.  If it melts your system to slag YOU are responsible, not
X *	   MCS or myself.  The burden rests with you to perform adaquate
X *	   testing before turning this loose on unsuspecting users.
X *
X *	Commercial distribution rights reserved; contact MCS at (708) 808-7200
X *	for details on commercial distribution licensing.
X *
X *	Compile with:  cc -s -o autouu autouu.c -lc_s -lx
X *
X */
X/*	Autobaud program 
X
X	Run in place of 'getty', this will prompt for a name
X	and call login just like the old one used to do... Only
X	difference is that it is rather interesting in it's interpretation
X	of what a 'gettydefs' file is; that is, there isn't one.
X	
X	We use modem return messages to determine the baud rate.  Locks are
X	respected as well, allowing the uucp system to share the ports.
X
X	You invoke this with:
X		/etc/autonew ttyA2 [code] [file]
X	
X	from /etc/inittab.  "[code]" is the numeric code for the baud rate
X	to send the initialization string at -- most of the time  you want
X	this to be the highest baud rate your modem will support.
X
X	Notes:
X		1) The device name does not have a prefix.  It is prepended
X		   automatically (/dev/ is added).
X		2) For ISC, use the MODEM CONTROL PORTS.  This program can
X		   interlock with UUCP; see their DEVICES file for the
X		   proper flags to set in the DEVICES and DIALERS files.
X		   Use the "new" definitions which have ",M" added (see your
X		   documentation for details).
X		3) While a port is being used for dialout, it will show
X		   up in a "who" command as "_Dialout" once data
X		   transmission begins.
X		4) Modes and owners will be changed on ports to prevent 
X		   random users from using the ports for "cu"s and other 
X		   communications uses.  This can be easily changed if 
X		   desired (look for the "chmod" call in the source).
X		5) The file /etc/autobaud.parm must be present if the "file"
X		   argument is missing.  If the "file" argument is present,
X		   it points to the control file to be used.  The format
X		   is as follows:
X			First line -- initialization string for ports
X			Second line -- response to initialization string
X			Third line -- Generic "connected" message
X			Up to first "#" alone -- baud codes, rates (text), and
X					 response strings expected.
X			Next line -- Login prompt
X			Remainder of file -- Issue file
X
X			Baud codes are the speed codes from termio.h; 
X			11, for example, is 2400 baud.
X
X			An example /etc/autobaud.parm file:
X				
X			AAATE0Q0V1
X			OK
X			CONNECTED
X			7 300 CONNECT
X			9 1200 CONNECT 1200
X			11 2400 CONNECT 2400
X			13 9600 CONNECT 9600
X			14 19200 CONNECT FAST
X			#
X			Login:
X
X			Welcome to the system
X			<EOF>
X		
X			This is a typical file for a system containing both
X			Telebit and low-speed modems (300-2400 baud).  Note
X			that the "AAA" is doubled to allow the Telebit to
X			autosync.  If you have hardware flow control then
X			enable it -- otherwise, set the modem up for
X			Xon/Xoff flow control, BREAK is sent and flushes,
X			Telebit S66=0 and S58=254 (Autobaud and prefer 
X			19200).  This permits full functionality with the 
X			exception of low-speed UUCP inbound calls through 
X			Telebits; if you have hardware flow control then no
X			restrictions apply.
X			
X		6) Your I/O board and/or drivers MUST correctly support the
X		   notion of O_NDELAY.  In addition, you have to be able to
X		   turn on and off the NDELAY flag with fcntl.  LOTS of
X		   intelligent boards broke this; if it's broken this
X		   program will NOT work.  ONE HACK:  If your NDELAY
X		   interpretation returns non-blocking if CD is down (with
X		   CLOCAL set and NDELAY cleared) this program will function
X		   correctly, although it will eat a small portion of CPU
X		   time to do so.
X		
X		7) Autobaud will wait for a carriage return and use it 
X		   to determine the parity of the caller's terminal (either
X		   8/N/1 or 7/E/1 only).  If the user doesn't press anything
X		   within a reasonable time frame, 8/N/1 is assumed.  The
X		   message "CONNECTED" is output to the user terminal
X		   immediately after autobaud senses the user's baud rate.
X
X		8) All modems served by a configuration must use the same 
X	 	   response sequences, although subsets are permitted (ie: the
X		   example file above would work for a USR Courier 2400 and
X		   a Telebit Trailblazer Plus equally well).
X
X	CHECK THE FUNCTIONS "checklock()" and "makelock()" -- they may need 
X	to be modified for your system!  In particular, some systems use 
X	binary PIDs and/or store the lock file in a different place.  We 
X	currently are set up for HDB UUCP on ISC 2.0.2/2.2.
X
X	Note that this program can share a port with a modem dialing out on
X	the same line!  It will perform with uucp on the same port without
X	trouble, so long as the locking is done correctly by uucp and other
X	programs which expect lock files.
X
X	Autobaud removes any stale lock files it finds automatically.
X
X*/
X
X#define		MAXISSUE	100		/* Lines in /etc/issue file */
X#define		MAXSECONDS	60			/* Timeout at start */
X#define		LOGSECONDS	90			/* Timeout at login */
X#define		UUCICO		"/usr/lib/uucp/uucico"	/* Where's uucico? */
X#define		BELL		7			/* Makes a "beep" */
X
extern	char	*malloc();
X
X#include	<stdio.h>
X#include	<fcntl.h>
X#include	<sys/types.h>
X#include	<sys/tty.h>
X#include	<utmp.h>
X#include	<signal.h>
X#include	<errno.h>
X#include	<termio.h>
X#include	<sys/stat.h>
X
X/*	Globals		*/
X
int	maschan = -1;		/* Nothing initially; master channel */
int	timeout = 0;		/* Timer value for keeping track of time */
XFILE	*ferr;			/* Error channel */
X
slowwrite(chan, str, len)	/* Write a string slowly to the port */
int	chan, len;
char	*str;
X{	
X	int 	x;
X	char	*ptr;
X	char	ch[2];
X
X	ptr = str;
X	for (x = 0; x < len; x++) {
X		ch[0] = *ptr;
X		write(chan, ch, 1);
X		nap(10);
X		ptr++;
X	}
X	return;
X}
X
checkmatch(matches, mcount, bfr, speed)		/* Any matches in array? */
struct	{
X	char	string[40];
X	int	baud;
X	char	speed[20];
X} matches[];
int	mcount;
char	bfr[];
char	speed[];
X{
X	int	x = 0;
X
X	for (x = 0; x < mcount; x++) {
X		if (!strcmp(bfr, matches[x].string)) {
X			strcpy(speed, matches[x].speed);
X			return(matches[x].baud);
X		}
X	}
X	return(0);
X}
X
X/* 	External declarations	*/
extern	struct	utmp	*getutent(), *pututline();
X
X
X/*	Makelock / Checklock - makes / checks for lock files
X	line		- the line to check for a lock
X	lockflag	- if non-zero, checklock will sleep until it sees the
X			  lock is gone, otherwise it returns status
X			  (checklock only)
X
Returns not zero (-1) if line is locked
X
X*/
X
int	makelock(line)
char	*line;
X{
X
char	tmp[80];
char	tmp2[80];
char	tbfr[20];
int	id;
XFILE	*id2;
int	pid;
struct	stat	st;
X
X	sprintf(tmp, "/usr/spool/locks/LTMP..%d", getpid());
X	sprintf(tmp2, "/usr/spool/locks/LCK..%s", line);
X	if ((id = open(tmp, O_WRONLY|O_CREAT, 0660)) < 0) {
X		exit(1);
X	}
X	sprintf(tbfr, "%10d\n", getpid());
X	tbfr[11] = 0;
X	write(id, tbfr, 11);
X	close(id);
X	if (!stat(UUCICO, &st)) {			/* Find ownership */
X		chown(tmp, st.st_uid, st.st_gid);	/* Set owner/group */
X	}
X	while (link(tmp, tmp2)) {
X		if ((id2 = fopen(tmp2, "r")) == (FILE *) NULL) {
X			sleep(1);			/* Slow down.. */
X			continue;
X		}
X		fscanf(id2, "%d", &pid);		/* Read PID from file */
X		fclose(id2);				/* Be nice.. */
X		if (!kill(pid, 0)) {			/* Oh oh, a process! */
X			return(-1);
X		}
X		unlink(tmp2);
X	}
X	unlink(tmp);
X	return(0);
X}
X
int	checklock(line, lockflag)
char	*line;
int	lockflag;		/* If non-zero, wait for open line */
X{
X
char	ltmp[10];
char	tmp[80];
int	pid;
XFILE	*id;
X	
X	strcpy(ltmp, line);
X	sprintf(tmp, "/usr/spool/locks/LCK..%s", ltmp);	/* Where are locks? */
X	while (!access(tmp, 0)) {			/* If file is there */
X		if ((id = fopen(tmp, "r")) != (FILE *) NULL) {	/* opened? */
X			fscanf(id, " %d", &pid);	/* Get pid from bfr */
X			fclose(id);			/* Clean up */
X			if (kill(pid, 0)) {	/* See if process is alive */
X				if (errno == ESRCH) {	/* Nope; it died */
X					unlink(tmp);	/* Clear lock */
X					continue;	/* Look again */
X				}
X			}
X			if (lockflag) {			/* IF waiting */
X				sleep(1);		/* Wait/keep going */
X			} else {
X				return(-1);		/* Else return locked */
X			}
X		}
X	}
X	return(0);					/* Line is clear */
X}
X
settogetty(line)			/* Mark process in Getty */
char	*line;
X{
X	int	pid;
X	struct	utmp	*u;
X	FILE	*fid;
X
X	pid = getpid();		/* Get our pid */
X	while ((u = getutent()) != NULL) {	/* While there are more lines */
X		if (((u->ut_type == INIT_PROCESS) || (u->ut_type == USER_PROCESS)) && (u->ut_pid == pid)) {
X			strcpy(u->ut_line, line);	/* Set line name */
X			strcpy(u->ut_user, "_Idle");	/* And name */
X			u->ut_pid = getpid();		/* And pid */
X			u->ut_type = LOGIN_PROCESS;	/* And type */
X			pututline(u);			/* Do it */
X			if ((fid = fopen(WTMP_FILE, "a+")) != NULL) {
X				fseek(fid, 0L, 2);	/* Seek end */
X				fwrite((char *) u, sizeof(*u), 1, fid);
X				fclose(fid);		/* Wrote wtmp */
X			}
X			break;
X		}
X	}
X	endutent();
X	return;
X}
X
settologin(line)		/* Tell the system we're at login state */
char	*line;
X{
X	int	pid;
X	struct	utmp	*u;
X
X	pid = getpid();		/* Get our pid */
X	while ((u = getutent()) != NULL) {	/* While there are more lines */
X		if ((u->ut_type == LOGIN_PROCESS) && (u->ut_pid == pid)) {
X			strcpy(u->ut_line, line);
X			strcpy(u->ut_user, "LOGIN");	/* Change name.. */
X			pututline(u);
X		}
X	}
X	endutent();
X	return;
X}
X
setlocked(line)		/* Fake a utmp entry for dialout lines (flagging) */
char	*line;
X{
X	int	pid;
X	struct	utmp	*u;
X
X	pid = getpid();		/* Get our pid */
X	while ((u = getutent()) != NULL) {	/* While there are more lines */
X		if ((u->ut_type == INIT_PROCESS) && (u->ut_pid == pid)) {
X			strcpy(u->ut_line, line);	/* Set line name */
X			strncpy(u->ut_user, "_Dialout", 8);	/* "User" */
X/*			u->ut_type = LOGIN_PROCESS;	*//* If invisible */
X			u->ut_type = USER_PROCESS;	/* It's visible */
X			pututline(u);
X		}
X	}
X	endutent();
X	return;
X}
X
X/*	Catch alarm signals	
X	Does two things -- catches the alarms, and also adds one to the
X	seconds counter.  If the user takes too long call 'hangup()' before
X	returning		*/
X
catch()
X{
X	signal(SIGALRM, catch);		/* Re-enable signal catcher */
X	if (timeout++ >= MAXSECONDS)
X		hangup();		/* Kill the user if he just sat */
X	return;				/* Do nothing else, just exit */
X}
X
X/*	Make upper case into lower case	*/
X
tlc(ptr)
char	*ptr;
X{
X	char	*pt;
X	int 	qm = 0;
X
X	pt = ptr;
X	while (*pt != 0) {
X		if ((*pt >= 'A') && (*pt <= 'Z')) {
X			*pt = *pt + 32;
X			qm++;
X		}
X		pt++;
X	}
X	if (qm) 
X		printf("%c\nWarning: Please use *lower* case on this system%c\n", BELL, BELL);
X	return;
X}
X
X
hangup()	 /*	Make sure the phone gets hung up when we exit	*/
X{
X	struct	termio	tt_array;
X	
X	if (maschan < 0)
X		exit(1);				/* Just exit */
X	if (ioctl(maschan, TCGETA, &tt_array)) {	/* No delay */
X		perror("Get parameter error");
X		exit(1);
X	}
X	tt_array.c_cflag &= ~(CBAUD|CLOCAL);		/* Set baud to 0 */
X	tt_array.c_cflag |= HUPCL|CREAD|CS8;		/* Set hangup */
X
X	if (ioctl(maschan, TCSETA, &tt_array)) {	/* No delay */
X		perror("Hang up error");
X		exit(1);
X	}
X	exit(0);
X}
X
X/*	Here is where all the fun begins; the main program 	*/
X
main(argc, argv)
int	argc;
char	*argv[];
X{
X	int	debug = 0;
X	int	x, ch, sw, status;
X	struct	termio	tt_array;
X	FILE	*fid, *fid2;
X	static	char	tmp[133], loginp[132];
X	extern	struct utmp *getutent(), *pututline();
X	char	baud[132];
X	char	connected[512];
X	int	fbaud = 0;
X	int	sbaud = 0;
X	char	line[80];
X	struct	stat	st;
X	char	init[80];
X	char	iresp[80];
X	int	initbaud;
X	char	speed[20];
X	struct	{
X		char	string[40];
X		int	baud;
X		char	speed[20];
X	} matches[20];
X	char	*istring[MAXISSUE];
X	int	mcount = 0;
X	int	bcount = 0;
X	int	icount = 0;
X	int	lcount = 0;
X	char	bc[2];
X	char	bfr[20];
X	int	satisfied = 0;
X	int	hoseline;
X	int	quit = 0;
X	int	stop = 0;
X
X	signal(SIGALRM, catch);			/* Catch alarms */
X	signal(SIGINT, SIG_IGN);		/* Ignore interrupts */
X	if (argc > 4)
X		debug++;
X	initbaud = atoi(argv[2]);		/* Initial baud rate */
X	strcpy(init, "ATZ\r");			/* Send this to init */
X	if (argc > 3) 
X		fid = fopen(argv[3], "r");	/* Try to open it */
X	else
X		fid = fopen("/etc/autobaud.parm", "r");	/* Try to open it */
X	if (fid != (FILE *) NULL) {
X		fgets(init, 80, fid);		/* Init string */
X		init[strlen(init) - 1] = '\r';	/* Make last a return */
X		fgets(tmp, 80, fid);
X		sscanf(tmp, " %s", iresp);
X		fgets(connected, 511, fid);	/* Connected string */
X		stop = 0;
X		while ((!stop) && (fgets(tmp, 80, fid) != (char *) NULL)) {
X			if ((tmp[0] == '#') && (strlen(tmp) <= 2)) {
X				stop++;
X				continue;
X			}
X			sscanf(tmp, "%d %[!-z] %[!-z ]", &matches[mcount].baud, matches[mcount].speed, matches[mcount].string);
X			mcount++;
X		}
X		lcount = MAXISSUE;
X		icount = 0;
X		fgets(loginp, 80, fid);			/* Get login prompt */
X		if (strlen(loginp))
X			loginp[strlen(loginp) - 1] = 0;	/* Chop off L/F */
X		while ((lcount) && (fgets(tmp, 132, fid) != (char *) NULL)) {	/* Get line */
X			istring[icount] = malloc(strlen(tmp) + 2);
X			strcpy(istring[icount++], tmp);
X			lcount--;
X		}
X		fclose(fid);
X	}
X	strcpy(line, argv[1]);			/* Look on this line */
X	setlocked(argv[1]);			/* Set port id to locked */
X	sprintf(tmp, "/dev/%s", line);		/* Check the line */
X	if (!stat(UUCICO, &st)) {		/* Who owns uucp? */
X		chown(tmp, st.st_uid, st.st_gid);/* Set line owner & group */
X		chmod(tmp, 0660);
X	}
X	checklock(line, 1);			/* Wait for no locks */
X	settogetty(argv[1]);			/* Mark us as in 'getty' */
X#ifndef	DEBUG
X	close(0);				/* Close stdin,stdout,stderr */
X	close(1);
X	close(2);
X	(void) setpgrp();			/* Make sure we have our own
X					   	   control terminal */
X#endif
X	sprintf(tmp, "/dev/%s", argv[1]);
X	if ((x = open(tmp, O_RDWR|O_NDELAY)) < 0) {/* BECOMES CONTROL TERM */
X		exit(1);			/* Exit; error! */
X	}					/* End of line.. */
X	maschan = x;				/* Master I/O channel */
X	tt_array.c_cflag = (HUPCL|CLOCAL|CS8|CREAD);
X	tt_array.c_cc[VMIN] = 1;
X	tt_array.c_cc[VTIME] = 1;		/* Set parameters */
X	ioctl(maschan, TCFLSH, 2);		/* Flush channel */
X	if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set DTR down */
X		exit(1);
X	}
X	sleep(1);
X	tt_array.c_cflag |= initbaud;		/* Set initial baud rate */
X	checklock(line, 0);			/* Exit if locked */
X	if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set parameters */
X		exit(1);
X	}
X	ioctl(maschan, TCFLSH, 2);		/* Flush channel */
X	sleep(1);
X	if ((status = fcntl(x, F_GETFL, 0)) != -1) {
X		status &= (~O_NDELAY);
X		if (fcntl(x, F_SETFL, status)) {	/* Clear O_NDELAY */
X			exit(0);
X		}
X	}
X	status = fcntl(maschan, F_GETFL, 0);	/* Read it again to be sure */
X	sleep(1);				/* Allow modem to settle */
X	checklock(line, 0);			/* Exit if locked */
X	timeout = 0;				/* No timeout yet */
X	slowwrite(maschan, init, strlen(init));/* Write initialization */
X	if (debug)
X		fprintf(ferr, "%x\n", status);
X	signal(SIGALRM, hangup);		/* Quit on timeout */
X	bcount = 0;
X	alarm(5);				/* Wait 5 seconds tops */
X	while (!quit) {				/* Check return from init */
X		if (!read(maschan, bc, 1)) {	/* Look for a character */
X			sleep(1);
X			continue;
X		}
X		if (debug)
X			fprintf(ferr, " %d\n", bc[0]);
X		if ((bc[0] == 10) || (bc[0] == 13)) {
X			if (strcmp(bfr, iresp)) {/* If not correct response */
X				bcount = 0;	/* Then drop it */
X				continue;	/* Keep looking */
X			} else {
X				quit++;		/* Else done */
X			}
X		} else {
X			bfr[bcount++] = bc[0];	/* Save character */
X			bfr[bcount] = 0;	/* Null terminate */
X		}
X	}
X	dup(maschan);
X	dup(maschan);	
X	ioctl(maschan, TCFLSH, 2);
X	ioctl((maschan + 1), TCFLSH, 2);
X	ioctl((maschan + 2), TCFLSH, 2);
X	ferr = fopen("/dev/console", "w");	/* Write to console for errs */
X	alarm(0);				/* Turn off timeout */
X	strcpy(line, argv[1]);			/* Look on this line */
X	if (checklock(line, 0))			/* Check lock status again */
X		exit(0);			/* Exit if line is locked */
X	satisfied = 0;
X	bcount = 0;				/* Nothing in buffer */
X	signal(SIGALRM, hangup);
X	alarm(1800);				/* 30 minutes idle time */
X	while (!satisfied) {			/* Read result codes */
X		if (!read(maschan, bc, 1)) {	/* Look for a character */
X			sleep(2);
X			continue;
X		}
X		if (checklock(line, 0))		/* Locked by someone else? */
X			exit(0);		/* Quit if so */
X		if ((bc[0] == 10) || (bc[0] == 13)) {	/* New line? */
X			satisfied = checkmatch(matches, mcount, bfr, speed);
X			if (!satisfied) {
X				bcount = 0;
X			}
X		} else {
X			bfr[bcount++] = bc[0];		/* Store character */
X			bfr[bcount] = 0;		/* Null terminate */
X		}
X	}
X	alarm(0);
X	if (makelock(line)) {			/* This is VERY bad! */
X		exit(0);			/* Quit right now! */
X	}
X	ioctl(maschan, TCGETA, &tt_array);
X	tt_array.c_cflag &= (~CBAUD);	/* Clear baud rate bits */
X	tt_array.c_cflag |= satisfied;	/* Set new baud rate */
X	ioctl(maschan, TCSETAW, &tt_array);
X	sprintf(baud, "%s @ %s bps", line, speed);
X	fid2 = fdopen(maschan, "a+");	/* Give us a stream channel please */
X	ioctl(maschan, TCFLSH, 2);	/* Flush input & output */
X	sleep(1);			/* Wait a second for settling... */
X	fprintf(fid2, "%s\r\n", connected);
X	fflush(fid2);
X	signal(SIGALRM, catch);
X	timeout = 0;
X	alarm(10);
X	if (read(maschan, bc, 1) > 0) {
X		switch(bc[0]) {
X			case 13:
X			case 10:
X				strcat(baud, ", 8/N/1");
X				goto aexit;		/* Do nothing */
X				break;
X			case -115:		/* If signed... */
X			case 141:		/* 7/E/1, but otherwise ok */
X				tt_array.c_cflag &= (~CS8);
X				tt_array.c_cflag |= (CS7|PARENB);
X				ioctl(maschan, TCSETAW, &tt_array);
X				ioctl((maschan + 1), TCSETAW, &tt_array);
X				ioctl((maschan + 2), TCSETAW, &tt_array);
X				strcat(baud, ", 7/E/1");
X				goto aexit;
X				break;
X			default:
X				break;
X		}
X	}
aexit:;
X	tt_array.c_cflag &= (~(CBAUD|CLOCAL));
X	tt_array.c_cflag |= (satisfied|HUPCL);	/* New baud rate */
X	tt_array.c_oflag |= OPOST|ONLCR;
X
X/*	If available, enable CTS flow control.  This is necessary for
X	Telebit Trailblazers and others of the general type.  Unfortunately,
X	only SCO has these things... (grr)  
X*/
X
X#ifdef	HARDWARE_FLOW
X	tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL;
X	tt_array.c_cflag |= HUPCL|CTSFLOW|RTSFLOW;
X#else
X	tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL|IXON|IXANY;
X	tt_array.c_cflag |= HUPCL;
X#endif
X	tt_array.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK;
X	tt_array.c_cc[VINTR] = 177;
X	tt_array.c_cc[VQUIT] = 0;
X	tt_array.c_cc[VERASE] = 8;
X	tt_array.c_cc[VKILL] = 21;
X	tt_array.c_cc[VEOF] = 4;
X	tt_array.c_cc[VEOL] = 0;
X	ioctl(maschan, TCSETAW, &tt_array);	/* Set parameters */
X	ioctl((maschan + 1), TCSETAW, &tt_array);
X	ioctl((maschan + 2), TCSETAW, &tt_array);
X	signal(SIGALRM, hangup);	/* If we time out, hang up the line */
X	alarm(LOGSECONDS);		/* LOGSECONDS to read/reply, then out */
X	fprintf(fid2, "\n[%s]\n", baud);/* Display parameters we found */
X	for (x = 0; x < icount; x++) {
X		fputs(istring[x], fid2);
X	}
X	fputs("\r\n", fid2);		/* End with another <return> */
bg1:;
X	fputs(loginp, fid2);		/* Prompt for login name */
X	fgets(tmp, 80, fid2);		/* Read it, but don't allow overrun */
X	if (*tmp == 10)			/* If nothing, ask again */
X		goto bg1;
X	tmp[strlen(tmp)-1] = 0;		/* Make sure null terminated */
X	tlc(tmp);			/* Lower case the name */
X	signal(SIGINT, SIG_DFL);	/* Reset signal handling */
X	signal(SIGALRM, SIG_DFL);
X	alarm(0);			/* Clear alarm */
X	fclose(ferr);			/* Close error channel */
X/*
X * Take two shots at where login is.  If we can't find it in either of these
X * places you're screwed; dump the caller.  Try to tell the user if this
X * happens, but no guarantees....
X */
X
X	execlp("/etc/login", "login", tmp, (char *) NULL);
X	execlp("/bin/login", "login", tmp, (char *) NULL);
X	fputs("Login not executable; contact administrator\n", fid2);
X	fflush(fid2);			/* Make sure it's printed */
X	sleep(3);			/* Wait for output to drain */
X	exit(1);			/* And quit with error (ignored) */
X}
X
END_OF_FILE
if test 19854 -ne `wc -c <'autouu.c'`; then
    echo shar: \"'autouu.c'\" unpacked with wrong size!
fi
# end of 'autouu.c'
fi
echo shar: End of shell archive.
exit 0

--
Karl Denninger (karl@ddsw1.MCS.COM, <well-connected>!ddsw1!karl)
Public Access Data Line: [+1 708 808-7300], Voice: [+1 708 808-7200]
Macro Computer Solutions, Inc.   "Quality Solutions at a Fair Price"