Ultrix-3.1/src/cmd/uucp/conn.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

#ifndef lint
static char sccsid[] = "@(#)conn.c	3.0 (decvax!larry) 4/22/86";
#endif


/*******
 *	conn(system)
 *	char *system;
 *
 *	conn - place a telephone call to system and
 *	login, etc.
 *
 *	return codes:
 *		CF_SYSTEM: don't know system
 *		CF_TIME: wrong time to call
 *		CF_DIAL: call failed
 *		CF_NODEV: no devices available to place call
 *		CF_LOGIN: login/password dialog failed
 *
 *		>0  - file no.  -  connect ok
 *
 *	decvax!larry - modifications to BSD4.2:
 *			- only ASSERT when adimistrative problem,  e.g
 *				L-devices set up wrong.   Otherwise
 *				return(FAIL).
 *			- fixline - changes for ULTRIX-11
 */

#include "uucp.h"
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#ifdef	SYSIII
#include <termio.h>
#include <fcntl.h>
#endif
#ifndef	SYSIII
#include <sgtty.h>
#endif

#define MAXC 1000

extern jmp_buf Sjbuf;
extern int errno;
int nulldev();

/* Parity control during login procedure */
#define	P_ZERO	0
#define	P_ONE	1
#define	P_EVEN	2
#define	P_ODD	3
char	par_tab[128];	/* must be power of two */

int next_fd = -1;	/* predicted fd to close interrupted opens */
				/* rti!trt, courtesy unc!smb */
/***
 *	alarmtr()  -  catch alarm routine for "expect".
 */
alarmtr()
{
	signal(SIGALRM, alarmtr);
	if (next_fd >= 0) {
		if (close(next_fd))
			logent("FAIL", "ACU LINE CLOSE");
		next_fd = -1;
	}
	longjmp(Sjbuf, 1);
}

int Dcf = -1;

conn(system)
char *system;
{
	int ret, nf;
	register int fn, fnd;
	char info[MAXC], *flds[MAXC/10];
	register FILE *fsys;
	int fcode = 0;

	nf = 0;
	fnd = 0;


	fsys = fopen(SYSFILE, "r");
	ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);

	DEBUG(4, "finds %s\n", "called");
	while((nf = finds(fsys, system, info, flds)) > 0) {
		DEBUG(4, "getto %s\n", "called");
		if ((fn = getto(flds)) > 0) {
			fnd = 1;
			Dcf = fn;
			break;
		}
		fcode = (fn == FAIL ? CF_DIAL : fn);
	}
	fclose(fsys);

	if (nf <= 0)
		return(fcode ? fcode : nf);

	DEBUG(4, "login %s\n", "called");
	ret = login(nf, flds, fn);
	if (ret < 0) {
		clsacu();
		return(CF_LOGIN);
	}
	/* rti!trt:  avoid passing file to children */
	fioclex(fn);
	return(fn);
}

/***
 *	getto(flds)		connect to remote machine
 *	char *flds[];
 *
 *	return codes:
 *		>0  -  file number - ok
 *		FAIL  -  failed
 */

getto(flds)
register char *flds[];
{
	register struct condev *cd;
	int diropn();

	DEBUG(4, "call: no. %s ", flds[F_PHONE]);
	DEBUG(4, "for sys %s\n", flds[F_NAME]);

	CU_end = nulldev;
	for (cd = condevs; cd->CU_meth != NULL; cd++) {
		if (prefix(cd->CU_meth, flds[F_LINE])) {
			DEBUG(4, "Using %s to call\n", cd->CU_meth);
			return((*(cd->CU_gen))(flds));
			}
		}
	/* try using a direct connect */
	return(diropn(flds));	
	}

/***
 *	clsacu()	close call unit
 *
 *	return codes:  none
 */

int (*CU_end)() = nulldev;
clsacu()
{
	(*(CU_end))(Dcf);
	DEBUG(5,"clsacu entered\n", "");
/*  close done in each close routine
	if (close(Dcf) < 0) {
		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
		logent("clsacu", "NOT CLOSED by CU_clos");
	}
*/
	Dcf = -1;
	CU_end = nulldev;
}

/***
 *	exphone - expand phone number for given prefix and number
 *
 *	return code - none
 */

exphone(in, out)
register char *in, *out;
{
	FILE *fn;
	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
	char buf[BUFSIZ];
	register char *s1;

	if (!isalpha(*in)) {
		strcpy(out, in);
		return;
	}

	s1=pre;
	while (isalpha(*in))
		*s1++ = *in++;
	*s1 = '\0';
	s1 = npart;
	while (*in != '\0')
		*s1++ = *in++;
	*s1 = '\0';

	tpre[0] = '\0';
	if ((fn = fopen(DIALFILE, "r")) == NULL)
		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
	else {
		while (cfgets(buf, BUFSIZ, fn)) {
			sscanf(buf, "%s%s", p, tpre);
			if (strcmp(p, pre) == SAME)
				goto found;
			tpre[0] = '\0';
		}
		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
	found:;
		fclose(fn);
	}

	strcpy(out, tpre);
	strcat(out, npart);
	return;
}

/***
 *	rddev - read and decode a line from device file
 *
 *	return code - FAIL at end-of file; 0 otherwise
 */

rddev(fp, dev)
register struct Devices *dev;
FILE *fp;
{
	char *fdig();
	char buf[BUFSIZ];
	int na;

	if (!cfgets(buf, BUFSIZ, fp))
		return(FAIL);

	na = sscanf(buf, "%s%s%s%s%s", dev->D_type, dev->D_line,
	  dev->D_calldev, dev->D_class, dev->D_brand);
	ASSERT(na >= 4, "BAD DEVICE ENTRY", buf, 0);
	if (na != 5) dev->D_brand[0] = '\0';
	dev->D_speed = atoi(fdig(dev->D_class));
	return(0);
}

/***
 *	finds(fsys, sysnam, info, flds)	set system attribute vector
 *
 *	return codes:
 *		>0  -  number of arguments in vector - succeeded
 *		CF_SYSTEM  -  system name not found
 *		CF_TIME  -  wrong time to call
 */

finds(fsys, sysnam, info, flds)
char *sysnam, info[], *flds[];
FILE *fsys;
{
	char sysn[8];
	int na;
	int fcode = 0;

	/* format of fields
	 *	0 name;
	 *	1 time
	 *	2 acu/hardwired
	 *	3 speed
	 *	etc
	 */
	while (cfgets(info, MAXC, fsys) != NULL) {
		na = getargs(info, flds);
		sprintf(sysn, "%.7s", flds[F_NAME]);
		if (strcmp(sysnam, sysn) != SAME)
			continue;
		if (ifdate(flds[F_TIME]))
			/*  found a good entry  */
			return(na);
		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
		fcode = CF_TIME;
	}
	return(fcode ? fcode : CF_SYSTEM);
}

/***
 *	login(nf, flds, dcr)		do login conversation
 *	char *flds[];
 *	int nf;
 *
 *	return codes:  0  |  FAIL
 */

login(nf, flds, fn)
register char *flds[];
int nf, fn;
{
	register char *want, *altern;
	extern char *index();
	int k, ok;

	ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf);
	for (k = F_LOGIN; k < nf; k += 2) {
		want = flds[k];
		ok = FAIL;
		while (ok != 0) {
			altern = index(want, '-');
			if (altern != NULL)
				*altern++ = '\0';
			DEBUG(4, "wanted %s ", want);
			ok = expect(want, fn);
			DEBUG(4, "got %s\n", ok ? "?" : "that");
			if (ok == 0)
				break;
			if (altern == NULL) {
				logent("LOGIN", "FAILED");
				/* close *not* needed here. rti!trt */
				return(FAIL);
			}
			want = index(altern, '-');
			if (want != NULL)
				*want++ = '\0';
			sendthem(altern, fn);
		}
		sleep(2);
		if (k+1 < nf)
			sendthem(flds[k+1], fn);
	}
	return(0);
}


/* rti!trt: conditional table generation to support odd speeds */
/* Suggested in n44a.139 by n44!dan (Dan Ts'o) */
struct sg_spds {int sp_val, sp_name;} spds[] = {
#ifdef B50
	{  50,	 B50},
#endif
#ifdef B75
	{  75,	 B75},
#endif
#ifdef B110
	{ 110,	B110},
#endif
#ifdef B150
	{ 150,	B150},
#endif
#ifdef B200
	{ 200,	B200},
#endif
#ifdef B300
	{ 300,  B300},
#endif
#ifdef B600
	{600,	B600},
#endif
#ifdef B1200
	{1200, B1200},
#endif
#ifdef B1800
	{1800, B1800},
#endif
#ifdef B2000
	{2000, B2000},
#endif
#ifdef B2400
	{2400, B2400},
#endif
#ifdef B3600
	{3600, B3600},
#endif
#ifdef B4800
	{4800, B4800},
#endif
#ifdef B7200
	{7200, B7200},
#endif
#ifdef B9600
	{9600, B9600},
#endif
#ifdef B19200
	{19200,B19200},
#endif
	{0, 0}
};

/***
 *	fixline(tty, spwant)	set speed/echo/mode...
 *	int tty, spwant;
 *
 *	return codes:  none
 */
int linebaud;

fixline(tty, spwant)
int tty, spwant;
{
#ifdef	SYSIII
	struct termio ttbuf;
#endif
#ifndef	SYSIII
	struct sgttyb ttbuf;
#endif
	register struct sg_spds *ps;
	int speed = -1;
	int ret;

	for (ps = spds; ps->sp_val; ps++)
		if (ps->sp_val == spwant)
			speed = ps->sp_name;
	ASSERT(speed >= 0, "BAD SPEED", "", speed);
#ifdef	SYSIII
	ioctl(tty, TCGETA, &ttbuf);
	/* ttbuf.sg_flags = (ANYP|RAW);
	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
	ttbuf.c_iflag = (ushort)0;
	ttbuf.c_oflag = (ushort)0;
	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
	ttbuf.c_lflag = (ushort)0;
	ttbuf.c_cc[VMIN] = 6;
	ttbuf.c_cc[VTIME] = 1;
	ret = ioctl(tty, TCSETA, &ttbuf);
#endif
#ifndef	SYSIII
	ioctl(tty, TIOCGETP, &ttbuf);
	ttbuf.sg_flags = (ANYP|RAW);
	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
	ret = ioctl(tty, TIOCSETP, &ttbuf);
#endif
	ASSERT(ret >= 0, "RETURN FROM STTY", "", ret);
#ifdef V7M11
	ioctl(tty, TIOCSDTR, (struct sgttyb *)NULL);
#endif
#ifndef	SYSIII
	ioctl(tty, TIOCHPCL, STBNULL);
	ioctl(tty, TIOCEXCL, STBNULL);
#endif
	linebaud = spwant;
	return;
}


/* Bill Shannon recommends MR 2000, but that takes too much space on PDPs */
/* Actually, the 'expect' algorithm should be rewritten. */
#define MR 1000


/***
 *	expect(str, fn)	look for expected string
 *	char *str;
 *
 *	return codes:
 *		0  -  found
 *		FAIL  -  lost line or too many characters read
 *		some character  -  timed out
 */

expect(str, fn)
register char *str;
int fn;
{
	static char rdvec[MR];
	register char *rp = rdvec;
	int kr;
	char nextch;

	if (strcmp(str, "\"\"") == SAME)
		return(0);
	*rp = 0;
	if (setjmp(Sjbuf)) {
		return(FAIL);
	}
	signal(SIGALRM, alarmtr);
/* change MAXCHARTIME to MAXMSGTIME, outside while loop -- brl-bmd!dpk */
	alarm(MAXMSGTIME);
	while (notin(str, rdvec)) {
		kr = read(fn, &nextch, 1);
		if (kr <= 0) {
			alarm(0);
			DEBUG(4, "lost line kr - %d\n, ", kr);
			logent("LOGIN", "LOST LINE");
			return(FAIL);
		}
		{
		int c;
		c = nextch & 0177;
		DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
		}
		if ((*rp = nextch & 0177) != '\0')
			rp++;
/* Check rdvec before null termination -- cmcl2!salkind */
		if (rp >= rdvec + MR) {
			alarm(0);
			logent("LOGIN", "INPUT BUFFER EXCEEDED");
			return(FAIL);
		}
		*rp = '\0';
	}
	alarm(0);
	return(0);
}


/*
 * Determine next file descriptor that would be allocated.
 * This permits later closing of a file whose open was interrupted.
 * It is a UNIX kernel problem, but it has to be handled.
 * unc!smb (Steve Bellovin) probably first discovered it.
 */
getnextfd()
{
	close(next_fd = open("/", 0));
}

/***
 *	sendthem(str, fn)	send line of login sequence
 *	char *str;
 *
 *	return codes:  none
 */

sendthem(str, fn)
register char *str;
int fn;
{
	register char *strptr;
	int i, n, cr = 1;
	static int p_init = 0;

	/* Note: debugging authorized only for privileged users */
	DEBUG(5, "send %s\n", str);

	if (!p_init) {
		p_init++;
		bld_partab(P_EVEN);
	}

	if (prefix("BREAK", str)) {
		sscanf(&str[5], "%1d", &i);
		if (i <= 0 || i > 10)
			i = 3;
		/* send break */
		genbrk(fn, i);
		return;
	}

	if (prefix("PAUSE", str)) {
		sscanf(&str[5], "%1d", &i);
		if (i <= 0 || i > 10)
			i = 3;
		/* pause for a while */
		sleep((unsigned)i);
		return;
	}

	if (strcmp(str, "EOT") == SAME) {
		p_chwrite(fn, '\04');
		return;
	}

	/* LF, CR, and "" courtesy unc!smb */
	/* Send a '\n' */
	if (strcmp(str, "LF") == SAME)
		str = "\\n\\c";

	/* Send a '\r' */
	if (strcmp(str, "CR") == SAME)
		str = "\\r\\c";

	/* Set parity as needed */
	if (strcmp(str, "P_ZERO") == SAME) {
		bld_partab(P_ZERO);
		return;
	}
	if (strcmp(str, "P_ONE") == SAME) {
		bld_partab(P_ONE);
		return;
	}
	if (strcmp(str, "P_EVEN") == SAME) {
		bld_partab(P_EVEN);
		return;
	}
	if (strcmp(str, "P_ODD") == SAME) {
		bld_partab(P_ODD);
		return;
	}

	/* If "", just send '\r' */
	if (strcmp(str, "\"\"") != SAME)
	for (strptr = str; *strptr; strptr++) {
		if (*strptr == '\\') switch(*++strptr) {
		case 's':
			DEBUG(5, "BLANK\n", "");
			*strptr = ' ';
			break;
		case 'd':
			DEBUG(5, "DELAY\n", "");
			sleep(1);
			continue;
		case 'r':
			DEBUG(5, "RETURN\n", "");
			*strptr = '\r';
			break;
		case 'b':
			if (isdigit(*(strptr+1))) {
				i = (*++strptr - '0');
				if (i <= 0 || i > 10)
					i = 3;
			} else
				i = 3;
			/* send break */
			genbrk(fn, i);
			continue;
		case 'c':
			if (*(strptr+1) == '\0') {
			DEBUG(5, "NO CR\n", "");
				cr = 0;
				continue;
			}
			DEBUG(5, "NO CR - MIDDLE IGNORED\n", "");
			continue;
		default:
			if (isdigit(strptr[1])) {
				i = 0;
				n = 0;
				while (isdigit(strptr[1]) && ++n <= 3)
					i = i*8 + (*++strptr - '0');
				p_chwrite(fn, i);
				continue;
			}
			DEBUG(5, "BACKSLASH\n", "");
			strptr--;
		}
		p_chwrite(fn, *strptr);
	}

	/* '\n' changed to '\r'--a better default. rti!trt */
	if (cr)
		p_chwrite(fn, '\r');
	return;
}

p_chwrite(fd, c)
int fd;
int c;
{
	char t[2];

	t[0] = par_tab[c&0177];
	t[1] = '\0';
	ASSERT2(write(fd, t, 1) == 1, "BAD WRITE", "", t[0]);
}

/*
 * generate parity table for use by p_chwrite.
 */
bld_partab(type)
int type;
{
	register int i, j, n;

	for (i = 0; i < sizeof(par_tab); i++) {
		n = 0;
		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
			n++;
		par_tab[i] = i;
		if (type == P_ONE
		 || (type == P_EVEN && (n&01) != 0)
		 || (type == P_ODD && (n&01) == 0))
			par_tab[i] |= sizeof(par_tab);
	}
}

#define BSPEED B150

/***
 *	genbrk		send a break
 *
 *	return codes;  none
 */

genbrk(fn, bnulls)
register int fn, bnulls;
{
	register int ret;
#ifdef	SYSIII
	ret = ioctl(fn, TCSBRK, STBNULL);
	DEBUG(5, "break ioctl ret %d\n", ret);
#endif
#ifndef	SYSIII
#ifdef	TIOCSBRK
	ret = ioctl(fn, TIOCSBRK, STBNULL);
	DEBUG(5, "break ioctl ret %d\n", ret);
#ifdef	TIOCCBRK
	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
	ASSERT2(ret > 0, "BAD WRITE genbrk", "", ret);
	sleep(1);
	ret = ioctl(fn, TIOCCBRK, STBNULL);
	DEBUG(5, "break ioctl ret %d\n", ret);
#endif
	DEBUG(4, "ioctl 1 second break\n", STBNULL);
#else
	struct sgttyb ttbuf;
	register int sospeed;

	ret = ioctl(fn, TIOCGETP, &ttbuf);
	sospeed = ttbuf.sg_ospeed;
	ttbuf.sg_ospeed = BSPEED;
	ret = ioctl(fn, TIOCSETP, &ttbuf);
	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
	ASSERT2(ret > 0, "BAD WRITE genbrk", "", ret);
	ttbuf.sg_ospeed = sospeed;
	ret = ioctl(fn, TIOCSETP, &ttbuf);
	ret = write(fn, "@", 1);
	ASSERT2(ret > 0, "BAD WRITE genbrk", "", ret);
	DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
#endif
#endif
}


/***
 *	notin(sh, lg)	check for occurrence of substring "sh"
 *	char *sh, *lg;
 *
 *	return codes:
 *		0  -  found the string
 *		1  -  not in the string
 */

notin(sh, lg)
register char *sh, *lg;
{
	while (*lg != '\0') {
		/* Dave Martingale: permit wild cards in 'expect' */
		if (wprefix(sh, lg))
			return(0);
		else
			lg++;
	}
	return(1);
}


/*******
 *	ifdate(s)
 *	char *s;
 *
 *	ittvax!swatt
 *	Allow multiple date specifications separated by '|'.
 *	Calls ifadate, formerly "ifdate".
 *
 *	return codes:
 *		see ifadate
 */

ifdate(s)
char *s;
{
	register char *p;
	register int ret;

	for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|'))
		if (ret = ifadate(p))
			return(ret);
	return(0);
}


/*******
 *	ifadate(s)
 *	char *s;
 *
 *	ifadate  -  this routine will check a string (s)
 *	like "MoTu0800-1730" to see if the present
 *	time is within the given limits.
 *	SIDE EFFECT - Retrytime is set
 *
 *	String alternatives:
 *		Wk - Mo thru Fr
 *		zero or one time means all day
 *		Any - any day
 *
 *	return codes:
 *		0  -  not within limits
 *		1  -  within limits
 */

ifadate(s)
char *s;
{
	static char *days[]={
		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
	};
	time_t clock;
	int rtime;
	int i, tl, th, tn, flag, dayok=0;
	struct tm *localtime();
	struct tm *tp;
	char *index();
	char *p;

	/*  pick up retry time for failures  */
	/*  global variable Retrytime is set here  */
	if ((p = index(s, ',')) == NULL) {
		Retrytime = RETRYTIME;
	}
	else {
		i = sscanf(p+1, "%d", &rtime);
		if (i < 1 || rtime < 5)
			rtime = 5;
		Retrytime  = rtime * 60;
	}

	time(&clock);
	tp = localtime(&clock);
	while (isalpha(*s)) {
		for (i = 0; days[i]; i++) {
			if (prefix(days[i], s))
				if (tp->tm_wday == i)
					dayok = 1;
		}

		if (prefix("Wk", s))
			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
				dayok = 1;
		if (prefix("Any", s))
			dayok = 1;
		s++;
	}

	if (dayok == 0)
		return(0);
	i = sscanf(s, "%d-%d", &tl, &th);
	tn = tp->tm_hour * 100 + tp->tm_min;
	if (i < 2)
		return(1);
	if (th < tl)
		flag = 0;  /* set up for crossover 2400 test */
	else
		flag = 1;
	if ((tn >= tl && tn <= th)
	  || (tn >= th && tn <= tl)) /* test for crossover 2400 */
		return(flag);
	else
		return(!flag);
}


/***
 *	char *
 *	lastc(s)	return pointer to last character
 *	char *s;
 *
 */

char *
lastc(s)
register char *s;
{
	while (*s != '\0') s++;
	return(s);
}


/***
 *	char *
 *	fdig(cp)	find first digit in string
 *
 *	return - pointer to first digit in string or end of string
 */

char *
fdig(cp)
register char *cp;
{
	register char *c;

	for (c = cp; *c; c++)
		if (*c >= '0' && *c <= '9')
			break;
	return(c);
}


/*
 * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
 * Strings are compared as if they contain all capital letters.
 */

snccmp(s1, s2)
register char *s1, *s2;
{
	char c1, c2;

	if (islower(*s1)) c1 = toupper(*s1);
	else c1 = *s1;
	if (islower(*s2)) c2 = toupper(*s2);
	else c2 = *s2;

	while (c1 == c2) {
		if (*s1++=='\0')
			return(0);
		s2++;
		if (islower(*s1)) c1 = toupper(*s1);
		else c1 = *s1;
		if (islower(*s2)) c2 = toupper(*s2);
		else c2 = *s2;
	}
	return(c1 - c2);
}