xref: /csrg-svn/old/berknet/netdaemon.c (revision 8281)
1*8281Scomay static char sccsid[] = "@(#)netdaemon.c	4.3	(Berkeley)	10/02/82";
28193Smckusick 
38193Smckusick /* sccs id variable */
48193Smckusick static char *netdaemon_sid = "@(#)netdaemon.c	1.10";
58193Smckusick 
68193Smckusick /*
78193Smckusick 
88193Smckusick 	The daemon program that runs the network.
98193Smckusick 
108193Smckusick Usage:
118193Smckusick 	netdaemon -m mach [-r readfd] [-w writefd] [-d] [-h]
128193Smckusick 		[-os] [-or] [-ou num] [-p len] [-8] [-l]
138193Smckusick 
148193Smckusick Must be started by root.
158193Smckusick Options:
168193Smckusick 	-d		turn debugging on
178193Smckusick 	-h		use high-speed link (not implemented yet)
188193Smckusick 	-l		don't use net line discipline, even if available
198193Smckusick 	-m mach		remote machine is mach (required)
208193Smckusick 	-os		only send
218193Smckusick 	-or		only receive
228193Smckusick 	-ou num		only send things with uid = num
238193Smckusick 	-p num		length of packet
248193Smckusick 	-r num		if simulute w/pipes, read from num
258193Smckusick 	-w num		if simulate w/pipes, write on num
268193Smckusick */
278193Smckusick 
288193Smckusick # include "defs.h"
298193Smckusick /* take a time, adjust to be in PST, and divide by no of secs in a day */
308193Smckusick /* adjust by 10 mins, and day is considered to begin at 3AM */
318193Smckusick /* (6*3600 = 21600) + 17400 = 39000 */
328193Smckusick /* number of seconds in a day, usually 86400L */
338193Smckusick # define nsecday 86400L
348193Smckusick /* number of days since time began */
358193Smckusick # define numdays(S) ((S - 39000L)/nsecday)
368193Smckusick /* set my priority to normal */
378193Smckusick # define RENICE0() { if (getuid() == 0) { nice(-40); nice(20); nice(0); } }
388193Smckusick 
398193Smckusick /* global variables */
408193Smckusick extern char **environ;
418193Smckusick struct dumpstruc dump;
428193Smckusick struct bstruct btable[];
438193Smckusick struct daemonparms netd;
448193Smckusick struct userinfo status;
458193Smckusick 
468193Smckusick /* local variables */
478193Smckusick static long length;
488220Smckusick static DIR *dir;
498193Smckusick /* static char sheader[] = 		"ABCDE"; */
508193Smckusick static char tempfile[]= 	TEMPFILE;
518193Smckusick static char publogfile[]=  	PUBLOGFILE;
528193Smckusick static struct stat statbuf;
538193Smckusick int handlekill();
548193Smckusick static char frommach;
558193Smckusick long linechars();
568193Smckusick 
578193Smckusick main(argc,argv)
588193Smckusick   char **argv; {
598193Smckusick 	register int i;
608193Smckusick 	long ltime,t;
618193Smckusick 	char buf[100];
628193Smckusick 
638193Smckusick 	nice(-1);
648193Smckusick 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
658193Smckusick 		signal(SIGHUP, handlekill);
668193Smckusick 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
678193Smckusick 		signal(SIGQUIT, handlekill);
688193Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
698193Smckusick 		signal(SIGINT, handlekill);
708193Smckusick 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
718193Smckusick 		signal(SIGTERM, handlekill);
728193Smckusick 	debugflg = DBV;
738193Smckusick 	setupdaemon(argc,argv);
748193Smckusick 	/* now running alone as a daemon */
758193Smckusick 		/*
768193Smckusick 		for(i=0; i<15; i++)close(i);
778193Smckusick 		signal(SIGHUP,SIG_IGN);
788193Smckusick 		signal(SIGQUIT,SIG_IGN);
798193Smckusick 		signal(SIGINT,SIG_IGN);
808193Smckusick 		*/
818193Smckusick 	/* set the umask to a reasonable value */
828193Smckusick 	umask( 022 );
838193Smckusick 	senddir[strlen(senddir)-1] = remote;		/* choose dir */
848193Smckusick 	if(chdir(senddir) < 0){
858193Smckusick 		perror(senddir);
868193Smckusick 		exit(EX_OSFILE);
878193Smckusick 		}
888220Smckusick 	dir = opendir(senddir);
898193Smckusick 	if(dir == NULL){
908193Smckusick 		perror(senddir);
918193Smckusick 		exit(EX_OSFILE);
928193Smckusick 		}
938193Smckusick 	mktemp(tempfile);
948193Smckusick 	tempfile[strlen(tempfile) - 7] = remote;
958193Smckusick 	ltime = gettime();
968193Smckusick 	if(ltime == 0L)
978193Smckusick 		fprintf(stderr,"The network says 'The clock is set wrong.'\n");
988193Smckusick 	sprintf(buf,"net restarted to %s %d %s",longname(remote),
998193Smckusick 		getpid(),ctime(&ltime));
1008193Smckusick 	dump.longtime = ltime;
1018193Smckusick 	dump.lastndays = numdays(ltime);
1028193Smckusick 	addtolog(remote,buf);
1038193Smckusick 	addtopublic(buf);
1048193Smckusick 	fprintf(stderr,buf);
1058193Smckusick 	if(!debugflg)fclose(stderr);
1068193Smckusick 	sendpurge();
1078193Smckusick 	mainloop();
1088193Smckusick 	/* never returns */
1098193Smckusick }
1108193Smckusick /* the main loop of the daemon, alternatively rcv then send, if poss.*/
1118193Smckusick mainloop(){
1128193Smckusick 	register int i;
1138193Smckusick 
1148193Smckusick 	for(;;){	/* begin reading file */
1158193Smckusick 		debug("daemon %c %d\n",remote,getpid());
1168193Smckusick 		/* first receive */
1178193Smckusick 		if(netd.dp_sndorcv >= 0){	/* if we can receive */
1188193Smckusick 			i = netrcv();
1198193Smckusick 			if(i == -1)dump.nabnormal++;
1208193Smckusick 		}
1218193Smckusick 		/* now look to send */
1228193Smckusick 		if(netd.dp_sndorcv <= 0)	/* if we can send */
1238193Smckusick 			netsend();
1248193Smckusick 		/* print out statistics if the right time */
1258193Smckusick 		printstat();
1268193Smckusick 		dump.nloop++;
1278193Smckusick 	}
1288193Smckusick }
1298193Smckusick 	/* this code is a little strange because some machines
1308193Smckusick 	   seem to have trouble having the date set, and time()
1318193Smckusick 	   returns 0 until somebody remembers to set the date */
1328193Smckusick printstat(){
1338193Smckusick 	long thisndays, thistime;
1348193Smckusick 	thistime = gettime();
1358193Smckusick 	thisndays = numdays(thistime);
1368193Smckusick 	if(dump.longtime == 0L){
1378193Smckusick 		dump.longtime = thistime;
1388193Smckusick 		dump.lastndays = thisndays;
1398193Smckusick 		return;
1408193Smckusick 		}
1418193Smckusick 	if(thisndays == dump.lastndays + 1L) dumpit(thistime);
1428193Smckusick 	dump.lastndays = thisndays;
1438193Smckusick }
1448193Smckusick /* look for files to send */
1458193Smckusick netsend(){
1468193Smckusick 	static long lasttime = 0;
1478193Smckusick 	static char nleft = 1;
1488193Smckusick 	long lFileLen,diff;
1498193Smckusick 	double drate;
150*8281Scomay 	register int uid,uidBest;
1518193Smckusick 	char *sdate,*sn,*swait;
1528193Smckusick 	long ot,nt,filesize;
1538193Smckusick 	register int i;
1548193Smckusick 	char stemp[20];
1558193Smckusick 	static char jname[FNS];
1568220Smckusick 	register struct direct *dp;
1578193Smckusick 
1588193Smckusick 	debug("ck send");
1598193Smckusick 	if(stat(senddir,&statbuf) < 0){
1608193Smckusick 		error("%s %s",senddir,sys_errlist[errno]);
1618193Smckusick 		return;
1628193Smckusick 		}
1638193Smckusick 	if(statbuf.st_mtime == lasttime && nleft == 0)return;	/* no need to search */
1648193Smckusick 	lasttime = statbuf.st_mtime;
1658220Smckusick 	rewinddir(dir);
1668193Smckusick 	lFileLen = 10000000L;
1678193Smckusick 	nleft = 0;
1688220Smckusick 	while((dp = readdir(dir)) != NULL){
1698220Smckusick 		if(dp->d_name[0] != 'c'
1708220Smckusick 		   || dp->d_name[1] != 'f'
1718220Smckusick 		   || dp->d_name[2] != remote
1728220Smckusick 		   || stat(dp->d_name,&statbuf) < 0
1738193Smckusick 		   || statbuf.st_mode == 0)
1748193Smckusick 			continue;
1758220Smckusick 		dp->d_name[0] = 'd';
1768220Smckusick 		if(stat(dp->d_name,&statbuf) < 0 || statbuf.st_mode == 0)
1778193Smckusick 			continue;
1788193Smckusick 		uid = guid(statbuf.st_uid,statbuf.st_gid);
1798193Smckusick 		if(netd.dp_onlyuid != 0 && uid != netd.dp_onlyuid && uid != SUPERUSER
1808193Smckusick 			&& uid != NUID)continue;
1818193Smckusick 		nleft++;
1828193Smckusick 		filesize = getsize(&statbuf);
1838193Smckusick #ifndef DONTHOLDBIG
1848193Smckusick 		if( (filesize > MAXDAYFILE) && day() ) {
1858193Smckusick 			if( !debugflg )
1868193Smckusick 				continue;
1878193Smckusick 			else
1888220Smckusick 				debug("sending large file %s\n", dp->d_name );
1898193Smckusick 		}
1908193Smckusick #endif DONTHOLDBIG
1918193Smckusick 		if(lFileLen > filesize){
1928193Smckusick 			lFileLen = filesize;
1938220Smckusick 			strcpy(jname,dp->d_name);
1948193Smckusick 			uidBest = uid;
1958193Smckusick 		}
1968193Smckusick # ifdef MAXSENDQ
1978193Smckusick 		if(nleft > MAXSENDQ)break;
1988193Smckusick # endif MAXSENDQ
1998193Smckusick 	}
2008193Smckusick 	if(lFileLen == 10000000L)return;
2018193Smckusick 	strcpy(stemp,jname);
2028193Smckusick 	stemp[0] = 'c';
2038193Smckusick 	sn = SnFromUid(uidBest);
2048193Smckusick 	if(sn == NULL){
2058193Smckusick 		addtolog(remote,"Unknown userid %d\n",uidBest);
2068193Smckusick 		addtolog(remote,"Removing %s\n",stemp);
2078193Smckusick 		unlink(stemp);
2088193Smckusick 		return;
2098193Smckusick 	}
2108193Smckusick 	addtolog(remote,"^S %s %c: %s ",sn,remote,jname+2);
2118193Smckusick 	ot = gettime();
2128193Smckusick 	if(send(jname) == 0)return;
2138193Smckusick 	nt = gettime();
2148193Smckusick 	filesize = getsize(&statbuf);
2158193Smckusick 	unlink(jname);
2168193Smckusick 	unlink(stemp);
2178193Smckusick 	diff = nt - ot;
2188193Smckusick 	if(diff < 1)diff = 1;		/* avoid dividing by zero */
2198193Smckusick 	sdate = ctime(&nt)+4;
2208193Smckusick 	sdate[strlen(sdate) -9] = 0;
2218193Smckusick 	swait = comptime(ot - statbuf.st_mtime);
2228193Smckusick 	jname[3] = jname[2];
2238193Smckusick # ifndef NOFP
2248193Smckusick 	drate = (double)filesize / (double)diff;
2258193Smckusick 	addtolog(remote,"^T%c(%s, %ldb, %ldsec, %4.1fb/sec, w %s)\n",
2268193Smckusick 		remote,sdate,filesize, diff,drate, swait);
2278193Smckusick # else NOFP
2288193Smckusick 	addtolog(remote,"^T%c(%s, %ldb, %ldsec, w %s)\n",
2298193Smckusick 		remote,sdate,filesize, diff,swait);
2308193Smckusick # endif NOFP
2318193Smckusick 	addtopublic("%s: sent %-8s to %s (%s, %ld b, wait %s)\n",
2328193Smckusick 		sdate,sn,longname(remote),jname+3,filesize,swait);
2338193Smckusick 	dump.nsend++;
2348193Smckusick 	dump.bytetot += filesize;
2358193Smckusick 	dump.elaptot += diff;
2368193Smckusick 	}
2378193Smckusick 
2388193Smckusick /*
2398193Smckusick    day() returns 1 if the time is between 6AM and 12PM
2408193Smckusick */
2418193Smckusick day()
2428193Smckusick {
2438193Smckusick 	int hour;
2448193Smckusick 	long t;
2458193Smckusick 	char *ctime();
2468193Smckusick 
2478193Smckusick 	time( &t );
2488193Smckusick 	sscanf( ctime( &t ), "%*s%*s%*s%2d", &hour );
2498193Smckusick 	if( (hour>=0) && (hour<6) )
2508193Smckusick 		return( 0 );		/* night */
2518193Smckusick 	else
2528193Smckusick 		return( 1 );		/* day */
2538193Smckusick }
2548193Smckusick 
255*8281Scomay int subs;
256*8281Scomay 
2578193Smckusick send(jname)
2588193Smckusick 	char *jname;
2598193Smckusick {	/* push those bytes */
2608193Smckusick 	/* returns 0 if send fails, 1 otherwise */
2618193Smckusick 	register int n;
2628193Smckusick 	int i;
2638193Smckusick 	long lsize;
2648193Smckusick 	char mbuf[20], buf[MAXNBUF];
2658193Smckusick 	register char *p;
2668193Smckusick 	register FILE *jfile;
2678193Smckusick 
2688193Smckusick 	debug("send %s",jname);
2698193Smckusick 	if(stat(jname,&statbuf) < 0)goto sfail;
2708193Smckusick 	lsize = getsize(&statbuf);
2718193Smckusick 	if(lsize < MINSIZE){		/* all files are at least this long */
2728193Smckusick 		unlink(jname);
2738193Smckusick 		jname[0] = 'c';
2748193Smckusick 		unlink(jname);
2758193Smckusick 		return(1);
2768193Smckusick 		}
2778193Smckusick 	jfile = fopen(jname,"r");
2788193Smckusick 	if(jfile == NULL)goto sfail;
2798193Smckusick 	/*
2808193Smckusick 	strcpy(mbuf,sheader);
2818193Smckusick 	i = strlen(sheader);
2828193Smckusick 	p = (char *)&lsize;
2838193Smckusick 	lsize = fixuplong(lsize);
2848193Smckusick 	mbuf[i] = *p++;
2858193Smckusick 	mbuf[i+1] = *p++;
2868193Smckusick 	mbuf[i+2] = *p++;
2878193Smckusick 	mbuf[i+3] = *p++;
2888193Smckusick 	i = i + 4;
2898193Smckusick 	sendreset();
2908193Smckusick 	*/
2918193Smckusick 	initseqno();
2928193Smckusick 	sprintf(mbuf,"|%08ld|",lsize);
2938193Smckusick 	i = 10;
2948193Smckusick 	if(xwrite(mbuf,i) == WRITEFAIL)goto bwrite;
2958193Smckusick 	while((n=read(fileno(jfile),buf,MAXNBUF)) > 0)
2968193Smckusick 		if(xwrite(buf,n) == WRITEFAIL)goto bwrite;
2978193Smckusick 	fclose(jfile);
2988193Smckusick 	debug("end send");
2998193Smckusick 	return(1);
3008193Smckusick bwrite:
3018193Smckusick 	dump.nsendfail++;
3028193Smckusick 	fclose(jfile);
3038193Smckusick 	addtolog(remote,"^F%c\n",remote);
3048193Smckusick 	return(0);
3058193Smckusick sfail:
3068193Smckusick 	error("%s: %s",jname,sys_errlist[errno]);
3078193Smckusick 	dump.nsendfail++;
3088193Smckusick 	return(0);
3098193Smckusick 	}
3108193Smckusick netrcv(){
3118193Smckusick 	/* returns -2 in normal fail, -1 in abnormal fail, >= 0 otherwise */
3128193Smckusick 	char sin;
3138193Smckusick 	char mgetc(), *s;
3148193Smckusick 	register int n;
3158193Smckusick 	char c;
3168193Smckusick 	int i, dummy, pid;
3178193Smckusick 	unsigned rcode;
3188193Smckusick 	long otime,olength,diff,rcvfinish,nt;
3198193Smckusick 	double r;
3208193Smckusick 	char hbuf[20], buf[MAXNBUF];
3218193Smckusick 	register FILE *temp;
3228193Smckusick 	static struct header hd;
3238193Smckusick 
3248193Smckusick 	initseqno();
3258193Smckusick 	/*
3268193Smckusick 	n = nread(hbuf,strlen(sheader));
3278193Smckusick 	if(n == BROKENREAD)return(-2);
3288193Smckusick 	if(n != strlen(sheader) || strcmp(sheader,hbuf) != 0){
3298193Smckusick 		error("wrong head %d %s",n,hbuf);
3308193Smckusick 		return(-1);
3318193Smckusick 		}
3328193Smckusick 	n = nread(&length,4);
3338193Smckusick 	length = fixuplong(length);
3348193Smckusick 	*/
3358193Smckusick 	n = nread(hbuf,10);
3368193Smckusick 	if(n == BROKENREAD)return(-2);
3378193Smckusick 	if(n != 10){
3388193Smckusick 		error("bad length nread %d",n);
3398193Smckusick 		return(-1);
3408193Smckusick 		}
3418193Smckusick 	hbuf[10] = 0;
3428193Smckusick 	if(hbuf[0] != '|' || hbuf[9] != '|'){
3438193Smckusick 		error("poor format %s",hbuf);
3448193Smckusick 		return(-1);
3458193Smckusick 		}
3468193Smckusick 	hbuf[9] = 0;
3478193Smckusick 	length = atol(hbuf+1);
3488193Smckusick 	if(length < 0 || length > 100000000L){
3498193Smckusick 		error("bad length %ld",length);
3508193Smckusick 		return(-1);
3518193Smckusick 		}
3528193Smckusick 	dump.braw = 4;
3538193Smckusick 	olength = length;
3548193Smckusick 	otime = gettime();
3558193Smckusick 	debug("length = %ld\n",length);
3568193Smckusick 
3578193Smckusick /*
3588193Smckusick 	begin parsing header
3598193Smckusick 
3608193Smckusick 	from local to remote (requests)
3618193Smckusick 	code	net option	reason
3628193Smckusick 	q			normal request
3638193Smckusick 	y	-y		simply skips login check (used by netlpr)
3648193Smckusick 
3658193Smckusick 	from remote to local
3668193Smckusick 	code	net option	reason
3678193Smckusick 	w	-w		message to be written/mailed back
3688193Smckusick 	s	-z		normal response
3698193Smckusick */
3708193Smckusick 
3718193Smckusick 	i = readhd(&hd);
3728193Smckusick 	if(i == -3)goto forw;			/* being forwarded thru us */
3738193Smckusick 	if(i != 0)return(i);
3748193Smckusick 
3758193Smckusick 	strcpy(status.login, hd.hd_snto);
3768193Smckusick 	strcpy(status.localname,hd.hd_snfrom);
3778193Smckusick 
3788193Smckusick 	demask(hd.hd_spasswd);
3798193Smckusick 
3808193Smckusick 	s = hd.hd_scmdvirt;
3818193Smckusick 	while(*s && *s != ' ')s++;
3828193Smckusick 	c = *s;
3838193Smckusick 	*s = 0;
3848193Smckusick 	if(strcmp(hd.hd_scmdvirt,"netlpr") == 0)dump.nnetlpr++;
3858193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"netmail") == 0)dump.nnetmail++;
3868193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"mail") == 0)dump.nsmail++;
3878193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"netcp") == 0)dump.nnetcp++;
3888193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"response") == 0)dump.nresp++;
3898193Smckusick 	else dump.nnet++;
3908193Smckusick 	*s = c;
3918193Smckusick 
3928193Smckusick 	printhd(&hd);
3938193Smckusick 
3948193Smckusick 	/* any chars left are data */
3958193Smckusick forw:
3968193Smckusick 	sin = 0;
3978193Smckusick 	if(length > 0){	/* make a temp input file */
3988193Smckusick 		increment(tempfile);
3998193Smckusick 		temp = fopen(tempfile,"w");
4008193Smckusick 		if(temp == NULL){
4018193Smckusick 			error("%s %s",tempfile,sys_errlist[errno]);
4028193Smckusick 			return(-1);
4038193Smckusick 			}
4048193Smckusick 		chmod(tempfile,0600);
4058193Smckusick 		if(hd.hd_mchto != local){
4068193Smckusick 			fprintf(temp,"%c :%c :",hd.hd_code,hd.hd_mchto);
4078193Smckusick 			fflush(temp);
4088193Smckusick 		}
4098193Smckusick 		/* this is the loop to read in all the data */
4108193Smckusick 		while((n = mread(buf,MAXNBUF)) > 0)
4118193Smckusick 			if(write(fileno(temp),buf,n) != n){
4128193Smckusick 				error("%s %s",tempfile,sys_errlist[errno]);
4138193Smckusick 				fclose(temp);
4148193Smckusick 				unlink(tempfile);
4158193Smckusick 				return(-1);
4168193Smckusick 				};
4178193Smckusick 		fclose(temp);
4188193Smckusick 		if(n == BROKENREAD || length > 0){
4198193Smckusick 			unlink(tempfile);
4208193Smckusick 			return(-2);
4218193Smckusick 			}
4228193Smckusick 		sin = 1;
4238193Smckusick 		if(hd.hd_mchto != local){
4248193Smckusick 			diff = gettime() - otime;
4258193Smckusick 			if(diff < 1)diff = 1;	/* avoid dividing by 0 */
4268193Smckusick # ifndef NOFP
4278193Smckusick 			r = olength;
4288193Smckusick 			r = r/diff;
4298193Smckusick 			addtolog(remote,"^P(to %c, %ldb, %ldsec, %4.1fb/sec)\n",
4308193Smckusick 				hd.hd_mchto,olength,diff,r);
4318193Smckusick # else NOFP
4328193Smckusick 			addtolog(remote,"^P(to %c, %ldb, %ldsec)\n",
4338193Smckusick 				hd.hd_mchto,olength,diff);
4348193Smckusick # endif NOFP
4358193Smckusick 			dump.npass++;
4368193Smckusick 			dump.bytetot += olength;
4378193Smckusick 			dump.elaptot += diff;
4388193Smckusick 			while((pid = fork()) == -1)sleep(2);
4398193Smckusick 			if(pid == 0){
4408193Smckusick 				RENICE0();
4418193Smckusick #ifdef CCV7
4428193Smckusick 				/* make sure the spawned child has it's own
4438193Smckusick 					group process to avoid the nasty
4448193Smckusick 					"try again" message
4458193Smckusick 				*/
4468193Smckusick 				setpgrp();
4478193Smckusick #endif CCV7
4488193Smckusick 				execl(netcmd,"net","-x","-m",longname(hd.hd_mchto),
4498193Smckusick 					"-s",tempfile,0);
4508193Smckusick 				error("%s: %s",netcmd,sys_errlist[errno]);
4518193Smckusick 				exit(EX_UNAVAILABLE);
4528193Smckusick 				}
4538193Smckusick 			wait(&rcode);
4548193Smckusick 			unlink(tempfile);
4558193Smckusick 			rcode >>= 8;
4568193Smckusick 			if(rcode != 0)
457*8281Scomay 				error("pass-thru rcode %d", rcode);
4588193Smckusick 			debug("passthru to %c code %c rcode %d",
4598193Smckusick 				hd.hd_mchto,hd.hd_code,rcode);
4608193Smckusick 			return(1);
4618193Smckusick 			}
4628193Smckusick 		}
4638193Smckusick 	if(length > 0){error("file too short"); return(-1); }
4648193Smckusick 	rcvfinish = gettime();
4658193Smckusick 
4668193Smckusick 	while((pid = fork()) == -1)sleep(2);
4678193Smckusick 	if(pid > 0){
468*8281Scomay 		if (++subs > 10)
469*8281Scomay 			while( wait(&dummy) != -1) --subs;
4708193Smckusick 		return(1);	/* normal return */
4718193Smckusick 	}
4728193Smckusick 	/* this is a child, who will go ahead and execute the command */
4738193Smckusick 	/* running uid=0 at this point */
4748193Smckusick 	RENICE0();
4758193Smckusick 	/* nice(0 set back to 0 */
4768193Smckusick #ifdef CCV7
4778193Smckusick 	/* separate group process */
4788193Smckusick 	setpgrp();
4798193Smckusick #endif CCV7
4808193Smckusick 
481*8281Scomay 
482*8281Scomay 	/*
4838193Smckusick 	while((pid = fork()) == -1)sleep(2);
4848193Smckusick 	if(pid != 0)exit(EX_OK);
485*8281Scomay 	*/
4868193Smckusick 
4878193Smckusick 	/* child process which forks and waits */
4888193Smckusick 	mktemp(resfile);
4898193Smckusick 	while((pid = fork()) == -1)sleep(2);
4908193Smckusick 	if(pid == 0){
4918193Smckusick 		/* child */
4928193Smckusick 		strcpy(status.loginshell,Bsh);
4938193Smckusick 		frommach = hd.hd_mchfrom;
4948193Smckusick 		n = check(&hd,(hd.hd_code == 'q'));
4958193Smckusick 		if(!n)errormsg(TRUE,&hd,NULL,
4968193Smckusick 			"Bad remote login/password '%s'",hd.hd_snto);
4978193Smckusick 		temp = fopen(resfile,"w");
4988193Smckusick 		if(temp == NULL)
4998193Smckusick 			errormsg(TRUE,&hd,NULL,
5008193Smckusick 			"Create file %s: %s",resfile,sys_errlist[errno]);
5018193Smckusick 		fclose(temp);
5028193Smckusick 		chmod(resfile,0600);
5038193Smckusick 		mchown(resfile,status.muid,status.mgid);
5048193Smckusick 		if(sin)
5058193Smckusick 			mchown(tempfile,status.muid,status.mgid);
5068193Smckusick 		else tempfile[0] = 0;
5078193Smckusick 		setgid(status.mgid);
5088193Smckusick 		setuid(status.muid);
5098193Smckusick 		/* after this point our gid, uid is the target user's */
5108193Smckusick 		excmd(&hd,resfile,tempfile);
5118193Smckusick 	}
5128193Smckusick 	/* parent */
5138193Smckusick 	wait(&rcode);
5148193Smckusick 	rcode = (((rcode&077400) >>8) &0177);
5158193Smckusick 	/*
5168193Smckusick 	fclose(stdin);
5178193Smckusick 	fclose(stdout);
5188193Smckusick 	fclose(stderr);
5198193Smckusick 	*/
5208193Smckusick 	if(sin)unlink(tempfile);
5218193Smckusick 	/*
5228193Smckusick 	   now send something back to the sender
5238193Smckusick 	   unless this was a response (file or message)
5248193Smckusick 	*/
5258193Smckusick 	if((hd.hd_code == 'q' || hd.hd_code == 'y')
5268193Smckusick 	&& (hd.hd_srespfile[0] || !hd.hd_fnonotify))
5278193Smckusick 		sndresponse(&hd,rcode);
5288193Smckusick 	unlink(resfile);
5298193Smckusick 	s = ctime(&rcvfinish);
5308193Smckusick 	s += 4;
5318193Smckusick 	s[strlen(s) -8] = 0;
5328193Smckusick 	diff = rcvfinish - otime;
5338193Smckusick 	if(diff < 1)diff = 1;		/* avoid dividing by zero */
5348193Smckusick 	dump.bytetot += olength;
5358193Smckusick 	dump.elaptot += diff;
5368193Smckusick 	sprintf(buf,"%s rcv  %c:%-8s (%s)",
5378193Smckusick 		s,hd.hd_mchfrom,hd.hd_snfrom,hd.hd_snto);
5388193Smckusick 	addtolog(remote,"%s C: %s\n",buf,hd.hd_scmdvirt);
5398193Smckusick 	addtopublic("%s R: %d C: %s\n",buf,rcode,hd.hd_scmdvirt);
5408193Smckusick 	nt = rcvfinish - hd.hd_ltimesent;
5418193Smckusick 	buf[0] = 0;
5428193Smckusick 	if(nt > 0L)sprintf(buf," took (%s)",comptime(nt));
5438193Smckusick # ifndef NOFP
5448193Smckusick 	r = olength;
5458193Smckusick 	r = r/diff;
5468193Smckusick 	addtolog(remote,"\t\tR: %d%s %ldb %ldsec %4.1fb/sec\n",
5478193Smckusick 		rcode,buf,olength,diff,r);
5488193Smckusick 	r = dump.braw;
5498193Smckusick 	r = r/diff;
5508193Smckusick 	addtolog(remote,"\t\t%4.1frb/sec %4.1f%% use\n",r,(r/linechars())*100L);
5518193Smckusick # else NOFP
5528193Smckusick 	addtolog(remote,"\t\tR: %d%s %ldb %ldsec\n",
5538193Smckusick 		rcode,buf,olength,diff);
5548193Smckusick # endif NOFP
5558193Smckusick 	exit(EX_OK);
5568193Smckusick 	/*UNREACHED*/
5578193Smckusick 	}
5588193Smckusick long linechars(){
5598193Smckusick 	if(netd.dp_inspeed == 13)return(960L);
5608193Smckusick 	else return(120L);
5618193Smckusick 	}
5628193Smckusick /*
5638193Smckusick 	execute the user's command
5648193Smckusick 	this procedure is executed with uid, gid of the user
5658193Smckusick */
5668193Smckusick excmd(phd,tempresfile,tempinfile)
5678193Smckusick 	register struct header *phd;
5688193Smckusick 	char *tempresfile, *tempinfile;
5698193Smckusick {
5708193Smckusick 	FILE *fd;
5718193Smckusick 	int i, uid;
5728193Smckusick 	register char *s, c;
5738193Smckusick 
5748193Smckusick 	uid = getuid();
5758193Smckusick 	uid = uidmask(uid);
5768193Smckusick 	status.muid = uidmask(status.muid);
5778193Smckusick 	if(uid != status.muid)error("setuid fails");
5788193Smckusick 	debug("uid: %u, gid: %u\n",uid,status.mgid);
5798193Smckusick 	/* check for allowed root commands, for security reasons */
5808193Smckusick 	if(uid == SUPERUSER){
5818193Smckusick 		s = phd->hd_scmdact;
5828193Smckusick 		while(*s && *s != ' ')s++;
5838193Smckusick 		c = *s;
5848193Smckusick 		*s = 0;
5858193Smckusick 		/* these are the only commands root may execute */
5868193Smckusick 		if(strcmp(phd->hd_scmdact,"cat")            	!= 0
5878193Smckusick 		&& strcmp(phd->hd_scmdact,MWRITECMD)        	!= 0
5888193Smckusick 		&& strcmp(phd->hd_scmdact,"/bin/cat")       	!= 0
5898193Smckusick 		&& strcmp(phd->hd_scmdact,"netrm")          	!= 0
5908193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/lib/tq")    	!= 0
5918193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/cc/lib/tq") 	!= 0
5928193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/lib/rtrrm") 	!= 0
5938193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/cc/lib/rtrrm")	!= 0
5948193Smckusick 		&& strcmp(phd->hd_scmdact,"lpr")            	!= 0)
5958193Smckusick 			errormsg(TRUE,phd,tempresfile,
5968193Smckusick 				"Not allowed to execute '%s' as root",
5978193Smckusick 				phd->hd_scmdact);
5988193Smckusick 		*s = c;
5998193Smckusick 		}
6008193Smckusick 	if(chdir(status.dir) < 0)
6018193Smckusick 		errormsg(TRUE,phd,tempresfile,
6028193Smckusick 			"chdir %s: %s",status.dir,sys_errlist[errno]);
6038193Smckusick 	setenv(status.dir);	/* set up v7 environment */
6048193Smckusick 	if(tempinfile[0])mreopen(TRUE,phd,tempresfile,tempinfile,"r",stdin);
6058193Smckusick 	else if(phd->hd_sinfile[0])mreopen(TRUE,phd,tempresfile,phd->hd_sinfile,"r",stdin);
6068193Smckusick 	else mreopen(TRUE,phd,tempresfile,"/dev/null","r",stdin);
6078193Smckusick 	if(phd->hd_code == 's' && phd->hd_soutfile[0]){
6088193Smckusick 		if(stat(phd->hd_soutfile,&statbuf) < 0
6098193Smckusick 		   || getsize(&statbuf) != 0)
6108193Smckusick 			errormsg(FALSE,phd,tempresfile,"Bad result file '%s'",phd->hd_soutfile);
6118193Smckusick 		mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout);
6128193Smckusick 		}
6138193Smckusick 	else if(phd->hd_soutfile[0]){
6148193Smckusick 		fd = fopen(phd->hd_soutfile,"w");
6158193Smckusick 		if(fd == NULL)
6168193Smckusick 			errormsg(TRUE,phd,tempresfile,"Open file %s: %s",
6178193Smckusick 				phd->hd_soutfile,sys_errlist[errno]);
6188193Smckusick 		fclose(fd);
6198193Smckusick 		mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout);
6208193Smckusick 		}
6218193Smckusick 	else mreopen(TRUE,phd,tempresfile,tempresfile,"a",stdout);
6228193Smckusick 	debug("exec '%s'\n",phd->hd_scmdact);
6238193Smckusick 	if(debugflg == 0){
6248193Smckusick 		/* cheat */
6258193Smckusick 		close(2);
6268193Smckusick 		dup(1);
6278193Smckusick 		/*
6288193Smckusick 		mreopen(TRUE,phd,tempresfile,tempresfile,"a",stderr);
6298193Smckusick 		*/
6308193Smckusick 		}
6318193Smckusick 	for(i=3;i<15;i++)close(i);
6328193Smckusick 	if(strcmp(phd->hd_scmdact,"cat") == 0
6338193Smckusick 	|| strcmp(phd->hd_scmdact,"/bin/cat") == 0)excat();
6348193Smckusick 	do {
6358193Smckusick 		mexecl(status.loginshell,"sh","-c",phd->hd_scmdact,0);
6368193Smckusick 		sleep(2);
6378193Smckusick 		} while(errno == ETXTBSY);
6388193Smckusick 	perror(status.loginshell);
6398193Smckusick 	exit(EX_UNAVAILABLE);
6408193Smckusick }
6418193Smckusick /*
6428193Smckusick 	send back a response
6438193Smckusick 
6448193Smckusick 	if errormsg was called the resfile should be unlinked,
6458193Smckusick 	to avoid two messages being sent there
6468193Smckusick */
6478193Smckusick sndresponse(phd,rcode)
6488193Smckusick unsigned rcode;
6498193Smckusick struct header *phd;
6508193Smckusick {
6518193Smckusick 	char cmdstr[BUFSIZ], buf[BUFSIZ];
6528193Smckusick 	int dummy;
6538193Smckusick 	long maxfile = MAXFILELARGE;
6548193Smckusick 	/* send response back if a response file
6558193Smckusick 	was given or if mail/write is allowed */
6568193Smckusick 	if(stat(resfile,&statbuf) < 0){
6578193Smckusick 		error("%s %s",resfile,sys_errlist[errno]);
6588193Smckusick 		return;
6598193Smckusick 		}
6608193Smckusick 	if(getsize(&statbuf) >= maxfile){
6618193Smckusick 		errormsg(TRUE,phd,"Result file too large - not sent");
6628193Smckusick 		return;
6638193Smckusick 		}
6648193Smckusick 	if(getsize(&statbuf) == 0){
6658193Smckusick 		/* response file specified, no output generated */
6668193Smckusick 		if(phd->hd_srespfile[0] != 0)return;
6678193Smckusick 		/* quiet option - no output and a rcode of 0 */
6688193Smckusick 		if(rcode == 0 && phd->hd_fquiet)return;
6698193Smckusick 	}
6708193Smckusick 	/* use both old and new mwrite parm lists */
6718193Smckusick 
6728193Smckusick 	if(phd->hd_srespfile[0])
6738193Smckusick 		sprintf(cmdstr,"-o %s cat",phd->hd_srespfile);
6748193Smckusick 	else sprintf(cmdstr,
6758193Smckusick "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -c \"'%s'\" -y %s -e %ld -r %d",
6768193Smckusick 	MWRITECMD, phd->hd_snfrom,phd->hd_sttyname,phd->hd_lttytime,
6778193Smckusick 	phd->hd_mchto,phd->hd_snto, phd->hd_scmdvirt,phd->hd_ltimesent-TIMEBASE,
6788193Smckusick 	phd->hd_addrfrom, phd->hd_addrto, phd->hd_lttytime,
6798193Smckusick 	phd->hd_scmdvirt, phd->hd_sttyname, phd->hd_ltimesent-TIMEBASE, rcode);
6808193Smckusick 
6818193Smckusick 	sprintf(buf,"%s -m%c -z -b -l %s -s %s -c response %s",
6828193Smckusick 		netcmd,phd->hd_mchfrom,phd->hd_snfrom,resfile,cmdstr);
6838193Smckusick 	dummy = system(buf);		/* execute command buf */
6848193Smckusick }
6858193Smckusick 
6868193Smckusick /*
6878193Smckusick 
6888193Smckusick 	excat
6898193Smckusick 	does nothing more than copy standard input to standard
6908193Smckusick 	output, like the cat command, but reports write errors.
6918193Smckusick 	Uses getc and putc rather than fwrite and fread because
6928193Smckusick 	the latter call getc and putc.
6938193Smckusick */
6948193Smckusick excat(){
6958193Smckusick 	register int n;
6968193Smckusick 	char buf[BUFSIZ];
6978193Smckusick 
6988193Smckusick 	errno = 0;
6998193Smckusick 	while((n = read(0,buf,BUFSIZ)) > 0){
7008193Smckusick 		if(write(1,buf,n) != n){
7018193Smckusick 			perror("filecat: stdout");
7028193Smckusick 			exit(EX_OSFILE);
7038193Smckusick 			}
7048193Smckusick 		}
7058193Smckusick 	if(errno){
7068193Smckusick 		perror("filecat: stdin");
7078193Smckusick 		exit(EX_OSFILE);
7088193Smckusick 	}
7098193Smckusick 	exit(EX_OK);
7108193Smckusick }
7118193Smckusick /* returns errors for netrcv() */
7128193Smckusick static readhd(phd)
7138193Smckusick register struct header *phd;
7148193Smckusick {
7158193Smckusick 	char cflag, sbuf[BUFSIZ], parmlist[PARMLIST], *cptr;
7168193Smckusick 	int i, code;
7178193Smckusick 	code = mgetc();
7188193Smckusick 	phd->hd_mchto = mgetc();
7198193Smckusick 	if(code != 'q' && code != 'y' && code != 'w' && code != 's'){
7208193Smckusick 		error("bad code");
7218193Smckusick 		return(-1);
7228193Smckusick 		}
7238193Smckusick 	phd->hd_code = code;
7248193Smckusick 	for(i = 0; i < MAXINX; i++)
7258193Smckusick 		if(phd->hd_mchto == inxtoch(i)) break;
7268193Smckusick 	if(i >= MAXINX){
7278193Smckusick 		error("bad phd->hd_mchto");
7288193Smckusick 		return(-1);
7298193Smckusick 		}
7308193Smckusick 	if(phd->hd_mchto != local)return(-3);	/* being forwarded through us */
7318193Smckusick 	phd->hd_mchfrom = mgetc();
7328193Smckusick 	phd->hd_vmajor = mgetc();
7338193Smckusick 	phd->hd_vminor = mgetc();
7348193Smckusick 	i = 0;
7358193Smckusick 	i += mgets(phd->hd_snto,NS);
7368193Smckusick 	i += mgets(phd->hd_spasswd,20);
7378193Smckusick 	i += mgets(phd->hd_sinfile,FNS);
7388193Smckusick 	i += mgets(phd->hd_soutfile,FNS);
7398193Smckusick 	i += mgets(phd->hd_srespfile,FNS);
7408193Smckusick 	i += mgets(phd->hd_snfrom,NS);
7418193Smckusick 
7428193Smckusick 	/* addrfrom is the person who sent this to us,
7438193Smckusick 	   addrto is the person who received the command, i.e.
7448193Smckusick 	   addrto is on this machine */
7458193Smckusick 	if(phd->hd_snfrom[0] == 0)strcpy(phd->hd_snfrom,"root");
7468193Smckusick 	sprintf(phd->hd_addrfrom,  "%s:%s",longname(phd->hd_mchfrom),phd->hd_snfrom);
7478193Smckusick 	sprintf(phd->hd_addrto,    "%s:%s",longname(phd->hd_mchto),phd->hd_snto);
7488193Smckusick 
7498193Smckusick 	i += mgets(phd->hd_sttyname,20);
7508193Smckusick 	if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx");
7518193Smckusick 	cflag = mgetc();
7528193Smckusick 	if(!phd->hd_mchfrom || !phd->hd_code || !cflag || !phd->hd_vmajor || !phd->hd_vminor){
7538193Smckusick 		error("mgetc fails");
7548193Smckusick 		return(-1);
7558193Smckusick 		}
7568193Smckusick 
7578193Smckusick 	cflag -= 'a';
7588193Smckusick 	phd->hd_fnonotify = (cflag & F_NONOTIFY);
7598193Smckusick 	phd->hd_fquiet = (cflag & F_QUIET);
7608193Smckusick 
7618193Smckusick 	phd->hd_vmajor -= 'a';
7628193Smckusick 	phd->hd_vminor -= 'a';
7638193Smckusick 
7648193Smckusick 	i += mgets(sbuf,BUFSIZ);
7658193Smckusick 	phd->hd_lttytime = 0;
7668193Smckusick 	sscanf(sbuf,"%lo",&phd->hd_lttytime);
7678193Smckusick 
7688193Smckusick 	i += mgets(parmlist,PARMLIST);
7698193Smckusick #ifdef CRN
7708193Smckusick 	cptr = parmlist;
7718193Smckusick 	while( *cptr != '(' )
7728193Smckusick 		cptr++;
7738193Smckusick 	*cptr = '\0';
7748193Smckusick 	strcpy( phd->hd_ijobno, parmlist );
7758193Smckusick 	*cptr = '(';
7768193Smckusick #else CRN
7778193Smckusick 	strcpy( phd->hd_ijobno, "XYZZ" );
7788193Smckusick #endif CRN
7798193Smckusick 	/* keep variable parameter list in crn slot */
7808193Smckusick 	parseparmlist(parmlist);
7818193Smckusick 
7828193Smckusick 	i += mgets(sbuf,BUFSIZ);		/* time sent */
7838193Smckusick 	sscanf(sbuf,"%ld",&phd->hd_ltimesent);
7848193Smckusick 	phd->hd_ltimesent += TIMEBASE;
7858193Smckusick 	i += mgetcmd(phd->hd_scmdact);
7868193Smckusick 	i += mgetcmd(phd->hd_scmdvirt);
7878193Smckusick 	if(i != 0){error("mgets fails"); return(-1);}
7888193Smckusick 	if(phd->hd_scmdvirt[0] == 0)strcpy(phd->hd_scmdvirt,phd->hd_scmdact);
7898193Smckusick 	return(0);
7908193Smckusick }
7918193Smckusick /*
7928193Smckusick    check() -- verify login name and password
7938193Smckusick    phd    = login,passwd
7948193Smckusick    fverify  = 1 if password must check
7958193Smckusick    Returns 1 if password is ok, 0 if not.
7968193Smckusick */
7978193Smckusick check(phd,fverify)	/* 1 if OK, 0 if not */
7988193Smckusick register struct header *phd;
7998193Smckusick int fverify;
8008193Smckusick {
8018193Smckusick 	char *sencpasswd, *u, *nullstr = "";
8028193Smckusick 	struct passwd *pwd;
8038193Smckusick #ifdef CRN
8048193Smckusick 	struct gecos *gcos;
8058193Smckusick #endif CRN
8068193Smckusick 	if(phd->hd_snto[0] == 0)return(!fverify);
8078193Smckusick 	debug("check: phd->hd_snto = %s\n", phd->hd_snto );
8088193Smckusick 	if(!goodacctname(phd->hd_snto))return(!fverify);
8098193Smckusick 	pwd = getpwnam(phd->hd_snto);
8108193Smckusick 	debug("got pwd=%d, pwd->pw_passwd = %s\n",pwd, pwd->pw_passwd);
8118193Smckusick 	if(pwd == NULL)return(!fverify);
8128193Smckusick 	if(*phd->hd_spasswd)sencpasswd = crypt(phd->hd_spasswd,pwd->pw_passwd);
8138193Smckusick 	else sencpasswd = nullstr;
8148193Smckusick 	debug("check: passwd(rcvd)=%s, passwd(file) = %s, passwd(encrypt)=%s\n", phd->hd_spasswd, pwd->pw_passwd, sencpasswd );
8158193Smckusick 
8168193Smckusick 	status.muid = guid(pwd->pw_uid,pwd->pw_gid);
8178193Smckusick 	status.mgid = pwd->pw_gid;
8188193Smckusick #ifdef CRN
8198193Smckusick 	if( (gcos=pwgecos( pwd->pw_gecos )) == NULL )
8208193Smckusick 		strcpy( status.jobno, MAGICCRN );
8218193Smckusick 	else
8228193Smckusick 		strcpy( status.jobno, gcos->gc_crn );
8238193Smckusick #else CRN
8248193Smckusick 	strcpy( status.jobno, "XYZZ");
8258193Smckusick #endif CRN
8268193Smckusick 	strcpy(status.dir,pwd->pw_dir);
8278193Smckusick 	strcpy(status.loginshell,pwd->pw_shell);
8288193Smckusick 	u = status.loginshell;
8298193Smckusick 	if(u[0] == 0 || strcmp("/bin/sbash",u) == 0)strcpy(u,Bsh);
8308193Smckusick 
8318193Smckusick 	getpwdf(pwd);
8328193Smckusick 	/* ignore network passwd */
8338193Smckusick 	/* acct is not a pair, acct is not "network", passwd is incorrect,
8348193Smckusick 	and verification is requested => passwd not ok */
8358193Smckusick 	if(!facctpaircheck(phd) && strcmp(phd->hd_snto,"network") != 0
8368193Smckusick 	&& strcmp(pwd->pw_passwd,sencpasswd) != 0 && fverify)
8378193Smckusick 		return(0);
8388193Smckusick 	return(1);	/* otherwise passwd ok */
8398193Smckusick 	}
8408193Smckusick mread(b,n)
8418193Smckusick   register int n; {
8428193Smckusick 	if(length <= 0)return(0);
8438193Smckusick 	if(length < n)n = length;
8448193Smckusick 	n = nread(b,n);
8458193Smckusick 	if(n != BROKENREAD)length -= n;
8468193Smckusick 	return(n);
8478193Smckusick 	}
8488193Smckusick char mgetc(){			/* returns 0 if fail */
8498193Smckusick 	register char c;
8508193Smckusick 	register int n;
8518193Smckusick 	char buf[3];
8528193Smckusick 	if((n=nread(buf,3)) == BROKENREAD)return(0);
8538193Smckusick 	if(n != 3){error("bad read %d",n); return(0); }
8548193Smckusick 	c = buf[0];
8558193Smckusick 	if(buf[1] != ' ' && buf[1] != ':'){error("Bad char %c",buf[1]); return(0); }
8568193Smckusick 	length -= 3;
8578193Smckusick 	if(length < 0){error("length wrong2 %ld",length); return(0); }
8588193Smckusick 	return(c);
8598193Smckusick 	}
8608193Smckusick /* read in string over the network wire */
8618193Smckusick /* put string in s, max length is maxlen */
8628193Smckusick mgets(s,maxlen)			/* returns 0 if ok, 1 if not */
8638193Smckusick   int maxlen;
8648193Smckusick   register char *s; {
8658193Smckusick 	register char *q;
8668193Smckusick 	register int n;
8678193Smckusick 	char c;
8688193Smckusick 	q = s;
8698193Smckusick 	for(;;) {
8708193Smckusick 		if((n=nread(&c,1)) == BROKENREAD){
8718193Smckusick 			*s = 0;
8728193Smckusick 			error("mgets %s",s);
8738193Smckusick 			return(1);
8748193Smckusick 			}
8758193Smckusick 		if(n == 0)break;
8768193Smckusick 		if(c == '\\'){
8778193Smckusick 			if((n=nread(&c,1)) == BROKENREAD){
8788193Smckusick 				*s = 0;
8798193Smckusick 				error("mgets %s",s);
8808193Smckusick 				return(1);
8818193Smckusick 				}
8828193Smckusick 			if(n == 0)break;
8838193Smckusick 			}
8848193Smckusick 		if(c == ' ')break;
8858193Smckusick 		if(maxlen-- > 0) *s++ = c;
8868193Smckusick 		}
8878193Smckusick 	*s = 0;
8888193Smckusick 	if(nread(&c,1) == BROKENREAD){
8898193Smckusick 		error("mgets %s",s);
8908193Smckusick 		return(1);
8918193Smckusick 		}
8928193Smckusick 	length -= (s - q + 2);
8938193Smckusick 	if(length < 0){error("length wrong1 %ld %s",length,q); return(-1); }
8948193Smckusick 	if(maxlen < 0)
8958193Smckusick 		error("mgets - string too long");
8968193Smckusick 	return(0);
8978193Smckusick 	}
8988193Smckusick mgetcmd(s)			/* returns 0 if succeed, 1 otherwise */
8998193Smckusick   char *s; {
9008193Smckusick 	int i,n;
9018193Smckusick 	char c;
9028193Smckusick 	i = 0;
9038193Smckusick 	for(;;){
9048193Smckusick 		if((n=nread(&c,1)) == BROKENREAD){
9058193Smckusick 			s[i] = 0;
9068193Smckusick 			error("mgetcmd %s",s);
9078193Smckusick 			return(1);
9088193Smckusick 			}
9098193Smckusick 		if(n <= 0 || c == '\n')break;
9108193Smckusick 		if(c == '\\'){
9118193Smckusick 			if(nread(&c,1) == BROKENREAD){
9128193Smckusick 				s[i] = 0;
9138193Smckusick 				error("mgetcmd %s",s);
9148193Smckusick 				return(1);
9158193Smckusick 				}
9168193Smckusick 			length--;
9178193Smckusick 			}
9188193Smckusick 		s[i++] = c;
9198193Smckusick 		length--;
9208193Smckusick 		}
9218193Smckusick 	s[i] = 0;
9228193Smckusick 	length--;
9238193Smckusick 	return(0);
9248193Smckusick 	}
9258193Smckusick increment(s)
9268193Smckusick  char *s; {
9278193Smckusick 	int i;
9288193Smckusick 	char *p;
9298193Smckusick 	i = strlen(s) - 1;
9308193Smckusick 	while(s[i] == '9')i--;
9318193Smckusick 	if(s[i] < '0' || s[i] > '9'){
9328193Smckusick 		p = s+i+1;
9338193Smckusick 		while(*p)*p++ = '0';
9348193Smckusick 		return;
9358193Smckusick 		}
9368193Smckusick 	(s[i])++;
9378193Smckusick 	i++;
9388193Smckusick 	while(s[i])s[i++] = '0';
9398193Smckusick 	return;
9408193Smckusick 	}
9418193Smckusick /* gather 24-hour stats and  mail to STATADDR */
9428193Smckusick /* should also gather stats on # error msgs */
9438193Smckusick dumpit(currt)
9448193Smckusick   long currt; {
9458193Smckusick 	register struct dumpstruc *p = &dump;
9468193Smckusick 	register int ntot;
9478193Smckusick 	long elapt;
9488193Smckusick 	double cputime,utime,stime,bs,rawbs;
9498193Smckusick 	char *sstartt;
9508193Smckusick 	FILE *fdm;
9518193Smckusick 	char froma[30];
9528193Smckusick 	struct tms tbf;
9538193Smckusick 
9548193Smckusick 	/* if STATADDR is a file, the mail program this call will
9558193Smckusick 	   ultimately execute must be able to deal with it,
9568193Smckusick 	   and the remote mail program must be able to write on the
9578193Smckusick 	   file, i.e. mode 666 */
9588193Smckusick 	sprintf(froma,"%s=>",longname(local));
9598193Smckusick 	strcat(froma,longname(remote));
9608193Smckusick 	fdm = mailopen(STATADDR,froma,1,0);
9618193Smckusick 	if(fdm == NULL)return;
9628193Smckusick 
9638193Smckusick 	/* calculate times */
9648193Smckusick 	elapt = currt - dump.longtime;
9658193Smckusick 	ntot = p->nnetcp + p->nnetmail + p->nsmail + p->nnetlpr
9668193Smckusick 		+ p->nresp + p->nnet;
9678193Smckusick 	sstartt = ctime(&dump.longtime) + 4;
9688193Smckusick 	sstartt[strlen(sstartt) - 9] = 0;
9698193Smckusick 
9708193Smckusick 	times(&tbf);
9718193Smckusick # ifndef NOFP
9728193Smckusick 	utime = tbf.tms_utime + tbf.tms_cutime;
9738193Smckusick 	stime = tbf.tms_stime + tbf.tms_cstime;
9748193Smckusick 	cputime = utime + stime;
9758193Smckusick 	if(elapt > 0)cputime = (cputime/elapt) * 100.0;
9768193Smckusick 	else cputime = 0.0;
9778193Smckusick 	utime = utime/60.0;
9788193Smckusick 	stime = stime/60.0;
9798193Smckusick 	cputime = cputime/60.0;
9808193Smckusick 	bs = p->bytetot;
9818193Smckusick 	if(p->elaptot > 0)bs = bs /p->elaptot;
9828193Smckusick 	else bs = 0.0;
9838193Smckusick # endif NOFP
9848193Smckusick 
9858193Smckusick 	/* print out the statistics */
9868193Smckusick 	fprintf(fdm,"Subject: %s, %s, time %s\n",
9878193Smckusick 		froma,sstartt, comptime(elapt));
9888193Smckusick 	fprintf(fdm,"Command summary:\n");
9898193Smckusick 	fprintf(fdm,"\t# sent %d\t# pass_thru %d\t# rcv %d:\t# netcp %d\n",
9908193Smckusick 		p->nsend,p->npass,ntot,p->nnetcp);
9918193Smckusick 	fprintf(fdm,"\t# netlpr %d\t# netmail %d\t# sendbmail %d\t# resp %d\n",
9928193Smckusick 		p->nnetlpr,p->nnetmail,p->nsmail,p->nresp);
9938193Smckusick 	fprintf(fdm,"Protocol summary:\n");
9948193Smckusick 	fprintf(fdm,"\t# pk_sent %d\t# pk_rcv %d\t# b_sent %ld\t# b_rcv %ld\n",
9958193Smckusick 		p->npacksent,p->npackrcv,p->nbytesent, p->nbytercv);
9968193Smckusick 	fprintf(fdm,
9978193Smckusick 		"\t# send_fails %d\t# retrans %d\t# abn %d\t\t# cksum_errs %d\n",
9988193Smckusick 		p->nsendfail,p->nretrans, p->nabnormal,p->ncksum);
9998193Smckusick # ifndef NOFP
10008193Smckusick 	fprintf(fdm,"Load:\tuser %4.1f\tsys %4.1f\tpct %5.2f\trate %6.1f\n",
10018193Smckusick 		utime,stime,cputime,bs);
10028193Smckusick 	rawbs = p->brawtot*100L;
10038193Smckusick 	rawbs = rawbs / linechars();
10048193Smckusick 	fprintf(fdm,"\trawbytes %ld\tuse %4.1f\n", p->brawtot,rawbs);
10058193Smckusick # endif NOFP
10068193Smckusick 	mailclose(fdm);
10078193Smckusick 
10088193Smckusick 	/* reset counters */
10098193Smckusick 	p->nbytesent = p->nbytercv = p->elaptot = p->bytetot = 0L;
10108193Smckusick 	p->nretrans = p->nloop = p->nabnormal = p->ncksum = 0;
10118193Smckusick 	p->npacksent = p->npackrcv = p->nnetcp = p->nnetmail = 0;
10128193Smckusick 	p->nsmail = p->nnetlpr = p->nnet = p->npass = 0;
10138193Smckusick 	p->nsend = p->nsendfail = 0;
10148193Smckusick 	dump.longtime = currt;
10158193Smckusick 	}
10168193Smckusick /* returns 1 if n is ok, 0 if not */
10178193Smckusick goodacctname(n)
10188193Smckusick   char *n; {
10198193Smckusick 	int i;
10208193Smckusick 	i = -1;
10218193Smckusick 	while(btable[++i].bname)
10228193Smckusick 		if(strcmp(btable[i].bname,n) == 0 &&
10238193Smckusick 			local == btable[i].bmach)return(0);
10248193Smckusick 	return(1);
10258193Smckusick 	}
10268193Smckusick demask(s)
10278193Smckusick   register char *s; {
10288193Smckusick /*
10298193Smckusick 	static char buf[20];
10308193Smckusick 	char skey[30];
10318193Smckusick 	makeuukey(skey,status.login,local);
10328193Smckusick 	strcpy(s,nbsdecrypt(s,skey,buf));
10338193Smckusick */
10348193Smckusick 	while(*s){
10358193Smckusick 		*s &= 0177;		/* strip quote bites */
10368193Smckusick 		*s++ ^= 040;		/* invert upper-lower */
10378193Smckusick 		}
10388193Smckusick 	}
10398193Smckusick /*VARARGS0*/
10408193Smckusick mreopen(fsendtofmach,phd,sfn,a,b,c){
10418193Smckusick /* simply handles errors by giving error msg */
10428193Smckusick 	if(freopen(a,b,c) == NULL)
10438193Smckusick 		errormsg(fsendtofmach,phd,sfn,"%s: %s",a,sys_errlist[errno]);
10448193Smckusick }
10458193Smckusick /*
10468193Smckusick 	addtopub(string, args)
10478193Smckusick 
10488193Smckusick 	add a message to the public logfile /usr/net/logfile.
10498193Smckusick 	note that the file must be writeable by everyone
10508193Smckusick 	if error messages from the netrcv subroutine
10518193Smckusick 	such as chdir errors are to be noticed.
10528193Smckusick */
10538193Smckusick /*VARARGS0*/
10548193Smckusick addtopublic(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n)
10558193Smckusick char *s;
10568193Smckusick {
10578193Smckusick 	static FILE *log = NULL;
10588193Smckusick 	if(log == NULL){
10598193Smckusick 		if(stat(publogfile,&statbuf) < 0)return;
10608193Smckusick 		log = fopen(publogfile,"a");
10618193Smckusick 		if(log == NULL)return;
10628193Smckusick 		}
10638193Smckusick 	fseek(log,0L,2);
10648193Smckusick 	fprintf(log,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n);
10658193Smckusick 	fflush(log);
10668193Smckusick 	}
10678193Smckusick /* set up a dummy environment for v7 /bin/sh */
10688193Smckusick setenv(home)
10698193Smckusick   char *home; {
10708193Smckusick 	static char *env[3],benv[2][50];
10718193Smckusick 	env[0] = benv[0];
10728193Smckusick 	env[1] = benv[1];
10738193Smckusick #ifdef CCV7
10748193Smckusick 	strcpy( env[0], "PATH=:.:/usr/cc/bin:/usr/ucb/bin" );
10758193Smckusick #else CCV7
10768193Smckusick 	strcpy(env[0],"PATH=:/bin:/usr/bin");
10778193Smckusick #endif CCV7
10788193Smckusick 	sprintf(env[1],"HOME=%s",home);
10798193Smckusick 	env[2] = 0;
10808193Smckusick 	environ = env;
10818193Smckusick 	}
10828193Smckusick /*
10838193Smckusick 	errormsg(fsendtofmach,phd,sfn,"string",arg(s))
10848193Smckusick 
10858193Smckusick 	Sends error message to user.
10868193Smckusick 	If fsendtofmach=TRUE, send to phd->hd_mchfrom, otherwise
10878193Smckusick 	send to phd->hd_mchto.
10888193Smckusick 	Also, if error occured during return of a "response",
10898193Smckusick 	send to local machine.
10908193Smckusick 
10918193Smckusick 	Note that errormsg can be called by the netrcv subroutine
10928193Smckusick 	after the setuid() call to the specific user, so the
10938193Smckusick 	user must be able to get off an error msg back to him,
10948193Smckusick 	and to write in the two log files.
10958193Smckusick 	Can't use -w,-x,-y,-z for the net cmd because must be root for those.
10968193Smckusick 
10978193Smckusick 	If sfn != NULL, then unlink sfn before exiting.
10988193Smckusick */
10998193Smckusick /*VARARGS0*/
11008193Smckusick errormsg(fsendtofmach,phd,sfn,s,a,b,c,d,e,f,g,h)
11018193Smckusick char fsendtofmach;
11028193Smckusick struct header *phd;
11038193Smckusick char *sfn,*s;
11048193Smckusick {
11058193Smckusick 	int rcode;
11068193Smckusick 	char errstr[BUFSIZ], cmdstr[BUFSIZ], rcmd[BUFSIZ];
11078193Smckusick 	char toadd[FNS], fromadd[FNS], mchto, mchfrom;
11088193Smckusick 	char snto[FNS], snfrom[FNS];
11098193Smckusick 
11108193Smckusick 	if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx");
11118193Smckusick 	/* will send to toadd, from fromadd */
11128193Smckusick 	if(!fsendtofmach || strcmp(phd->hd_scmdvirt,"response") == 0){
11138193Smckusick 		/* send to tomach mach, thus send to toaddr. */
11148193Smckusick 		/* if this is an error during a response, send to local mach. */
11158193Smckusick 		strcpy(toadd,  phd->hd_addrto);
11168193Smckusick 		strcpy(fromadd,phd->hd_addrfrom);
11178193Smckusick 	}
11188193Smckusick 	else {		/* send to remote mach, thus send back to addrfrom*/
11198193Smckusick 		strcpy(toadd,  phd->hd_addrfrom);
11208193Smckusick 		strcpy(fromadd,phd->hd_addrto);
11218193Smckusick 	}
11228193Smckusick 	sprintf(errstr,"Error: ");
11238193Smckusick 	sprintf(cmdstr,s,a,b,c,d,e,f,g,h);
11248193Smckusick 	strcat(errstr,cmdstr);
11258193Smckusick 	strcat(errstr,"\n");
11268193Smckusick 	addtolog(remote,errstr);
11278193Smckusick 	addtopublic(errstr);
11288193Smckusick 
11298193Smckusick 	mchto =   MchSFromAddr(snto,toadd);
11308193Smckusick 	mchfrom = MchSFromAddr(snfrom,fromadd);
11318193Smckusick 
11328193Smckusick 	sprintf(rcmd,
11338193Smckusick "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -y %s -c \"'%s'\" -e %ld",
11348193Smckusick 	MWRITECMD, snto, phd->hd_sttyname, phd->hd_lttytime,
11358193Smckusick 	local, snfrom,phd->hd_scmdvirt, phd->hd_ltimesent-TIMEBASE,
11368193Smckusick 	toadd, fromadd, phd->hd_lttytime, phd->hd_sttyname, phd->hd_scmdvirt,
11378193Smckusick 	phd->hd_ltimesent-TIMEBASE);
11388193Smckusick 
11398193Smckusick 	if(mchto == local)
11408193Smckusick 		sprintf(cmdstr, "echo \"%s\" | %s", errstr,rcmd);
11418193Smckusick 	else
11428193Smckusick 		sprintf(cmdstr,
11438193Smckusick 		"echo \"%s\" | %s -m%c -b -c errormessage -l network - %s",
11448193Smckusick 			errstr,netcmd,mchto,rcmd);
11458193Smckusick 	rcode = system(cmdstr);
11468193Smckusick 	debug( "errormsg: cmdstr = %s\n", cmdstr );
11478193Smckusick 	debug( "errormsg: rcode = %d\n", rcode );
11488193Smckusick 	if(sfn != NULL)unlink(sfn);
11498193Smckusick 	exit(EX_USAGE);
11508193Smckusick 	}
11518193Smckusick handlekill(){	/* SIGTERM signal */
11528193Smckusick 	long t;
11538193Smckusick 	/*
11548193Smckusick 	t = gettime();
11558193Smckusick 	dumpit(t);
11568193Smckusick 	*/
11578193Smckusick # ifdef NETLDISC
11588193Smckusick 	/* turn off net line discipline if possible */
11598193Smckusick 	netd.dp_linedis = 0;
11608193Smckusick 	ioctl(netd.dp_linefd,TIOCSETD,&netd.dp_linedis);
11618193Smckusick 	close(netd.dp_linefd);
11628193Smckusick 	printf("Network line discipline turned off.\n");
11638193Smckusick # endif NETLDISC
11648193Smckusick 	exit(EX_OK);	/* kill myself */
11658193Smckusick 	}
11668193Smckusick 
11678193Smckusick /* check a request to see if it is an acct pair */
11688193Smckusick /* returns 1 if it is, 0 if not */
11698193Smckusick static facctpaircheck(phd)
11708193Smckusick register struct header *phd;
11718193Smckusick {
11728193Smckusick 	return(0);
11738193Smckusick }
11748193Smckusick 
1175