xref: /csrg-svn/old/berknet/netdaemon.c (revision 8510)
1*8510Scomay static char sccsid[] = "@(#)netdaemon.c	4.5	(Berkeley)	10/13/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 
main(argc,argv)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.*/
mainloop()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 */
printstat()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 */
netsend()1458193Smckusick netsend(){
1468193Smckusick 	static long lasttime = 0;
1478193Smckusick 	static char nleft = 1;
1488193Smckusick 	long lFileLen,diff;
1498193Smckusick 	double drate;
1508281Scomay 	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 */
day()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 
send(jname)2558193Smckusick send(jname)
2568193Smckusick 	char *jname;
2578193Smckusick {	/* push those bytes */
2588193Smckusick 	/* returns 0 if send fails, 1 otherwise */
2598193Smckusick 	register int n;
2608193Smckusick 	int i;
2618193Smckusick 	long lsize;
2628193Smckusick 	char mbuf[20], buf[MAXNBUF];
2638193Smckusick 	register char *p;
2648193Smckusick 	register FILE *jfile;
2658193Smckusick 
2668193Smckusick 	debug("send %s",jname);
2678193Smckusick 	if(stat(jname,&statbuf) < 0)goto sfail;
2688193Smckusick 	lsize = getsize(&statbuf);
2698193Smckusick 	if(lsize < MINSIZE){		/* all files are at least this long */
2708193Smckusick 		unlink(jname);
2718193Smckusick 		jname[0] = 'c';
2728193Smckusick 		unlink(jname);
2738193Smckusick 		return(1);
2748193Smckusick 		}
2758193Smckusick 	jfile = fopen(jname,"r");
2768193Smckusick 	if(jfile == NULL)goto sfail;
2778193Smckusick 	/*
2788193Smckusick 	strcpy(mbuf,sheader);
2798193Smckusick 	i = strlen(sheader);
2808193Smckusick 	p = (char *)&lsize;
2818193Smckusick 	lsize = fixuplong(lsize);
2828193Smckusick 	mbuf[i] = *p++;
2838193Smckusick 	mbuf[i+1] = *p++;
2848193Smckusick 	mbuf[i+2] = *p++;
2858193Smckusick 	mbuf[i+3] = *p++;
2868193Smckusick 	i = i + 4;
2878193Smckusick 	sendreset();
2888193Smckusick 	*/
2898193Smckusick 	initseqno();
2908193Smckusick 	sprintf(mbuf,"|%08ld|",lsize);
2918193Smckusick 	i = 10;
2928193Smckusick 	if(xwrite(mbuf,i) == WRITEFAIL)goto bwrite;
2938193Smckusick 	while((n=read(fileno(jfile),buf,MAXNBUF)) > 0)
2948193Smckusick 		if(xwrite(buf,n) == WRITEFAIL)goto bwrite;
2958193Smckusick 	fclose(jfile);
2968193Smckusick 	debug("end send");
2978193Smckusick 	return(1);
2988193Smckusick bwrite:
2998193Smckusick 	dump.nsendfail++;
3008193Smckusick 	fclose(jfile);
3018193Smckusick 	addtolog(remote,"^F%c\n",remote);
3028193Smckusick 	return(0);
3038193Smckusick sfail:
3048193Smckusick 	error("%s: %s",jname,sys_errlist[errno]);
3058193Smckusick 	dump.nsendfail++;
3068193Smckusick 	return(0);
3078193Smckusick 	}
netrcv()3088193Smckusick netrcv(){
3098193Smckusick 	/* returns -2 in normal fail, -1 in abnormal fail, >= 0 otherwise */
3108193Smckusick 	char sin;
3118193Smckusick 	char mgetc(), *s;
3128193Smckusick 	register int n;
3138193Smckusick 	char c;
3148193Smckusick 	int i, dummy, pid;
3158193Smckusick 	unsigned rcode;
3168193Smckusick 	long otime,olength,diff,rcvfinish,nt;
3178193Smckusick 	double r;
3188193Smckusick 	char hbuf[20], buf[MAXNBUF];
3198193Smckusick 	register FILE *temp;
3208193Smckusick 	static struct header hd;
3218193Smckusick 
3228193Smckusick 	initseqno();
3238193Smckusick 	/*
3248193Smckusick 	n = nread(hbuf,strlen(sheader));
3258193Smckusick 	if(n == BROKENREAD)return(-2);
3268193Smckusick 	if(n != strlen(sheader) || strcmp(sheader,hbuf) != 0){
3278193Smckusick 		error("wrong head %d %s",n,hbuf);
3288193Smckusick 		return(-1);
3298193Smckusick 		}
3308193Smckusick 	n = nread(&length,4);
3318193Smckusick 	length = fixuplong(length);
3328193Smckusick 	*/
3338193Smckusick 	n = nread(hbuf,10);
3348193Smckusick 	if(n == BROKENREAD)return(-2);
3358193Smckusick 	if(n != 10){
3368193Smckusick 		error("bad length nread %d",n);
3378193Smckusick 		return(-1);
3388193Smckusick 		}
3398193Smckusick 	hbuf[10] = 0;
3408193Smckusick 	if(hbuf[0] != '|' || hbuf[9] != '|'){
3418193Smckusick 		error("poor format %s",hbuf);
3428193Smckusick 		return(-1);
3438193Smckusick 		}
3448193Smckusick 	hbuf[9] = 0;
3458193Smckusick 	length = atol(hbuf+1);
3468193Smckusick 	if(length < 0 || length > 100000000L){
3478193Smckusick 		error("bad length %ld",length);
3488193Smckusick 		return(-1);
3498193Smckusick 		}
3508193Smckusick 	dump.braw = 4;
3518193Smckusick 	olength = length;
3528193Smckusick 	otime = gettime();
3538193Smckusick 	debug("length = %ld\n",length);
3548193Smckusick 
3558193Smckusick /*
3568193Smckusick 	begin parsing header
3578193Smckusick 
3588193Smckusick 	from local to remote (requests)
3598193Smckusick 	code	net option	reason
3608193Smckusick 	q			normal request
3618193Smckusick 	y	-y		simply skips login check (used by netlpr)
3628193Smckusick 
3638193Smckusick 	from remote to local
3648193Smckusick 	code	net option	reason
3658193Smckusick 	w	-w		message to be written/mailed back
3668193Smckusick 	s	-z		normal response
3678193Smckusick */
3688193Smckusick 
3698193Smckusick 	i = readhd(&hd);
3708193Smckusick 	if(i == -3)goto forw;			/* being forwarded thru us */
3718193Smckusick 	if(i != 0)return(i);
3728193Smckusick 
3738193Smckusick 	strcpy(status.login, hd.hd_snto);
3748193Smckusick 	strcpy(status.localname,hd.hd_snfrom);
3758193Smckusick 
3768193Smckusick 	demask(hd.hd_spasswd);
3778193Smckusick 
3788193Smckusick 	s = hd.hd_scmdvirt;
3798193Smckusick 	while(*s && *s != ' ')s++;
3808193Smckusick 	c = *s;
3818193Smckusick 	*s = 0;
3828193Smckusick 	if(strcmp(hd.hd_scmdvirt,"netlpr") == 0)dump.nnetlpr++;
3838193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"netmail") == 0)dump.nnetmail++;
3848193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"mail") == 0)dump.nsmail++;
3858193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"netcp") == 0)dump.nnetcp++;
3868193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"response") == 0)dump.nresp++;
3878193Smckusick 	else dump.nnet++;
3888193Smckusick 	*s = c;
3898193Smckusick 
3908193Smckusick 	printhd(&hd);
3918193Smckusick 
3928193Smckusick 	/* any chars left are data */
3938193Smckusick forw:
3948193Smckusick 	sin = 0;
3958193Smckusick 	if(length > 0){	/* make a temp input file */
3968193Smckusick 		increment(tempfile);
3978193Smckusick 		temp = fopen(tempfile,"w");
3988193Smckusick 		if(temp == NULL){
3998193Smckusick 			error("%s %s",tempfile,sys_errlist[errno]);
4008193Smckusick 			return(-1);
4018193Smckusick 			}
4028193Smckusick 		chmod(tempfile,0600);
4038193Smckusick 		if(hd.hd_mchto != local){
4048193Smckusick 			fprintf(temp,"%c :%c :",hd.hd_code,hd.hd_mchto);
4058193Smckusick 			fflush(temp);
4068193Smckusick 		}
4078193Smckusick 		/* this is the loop to read in all the data */
4088193Smckusick 		while((n = mread(buf,MAXNBUF)) > 0)
4098193Smckusick 			if(write(fileno(temp),buf,n) != n){
4108193Smckusick 				error("%s %s",tempfile,sys_errlist[errno]);
4118193Smckusick 				fclose(temp);
4128193Smckusick 				unlink(tempfile);
4138193Smckusick 				return(-1);
4148193Smckusick 				};
4158193Smckusick 		fclose(temp);
4168193Smckusick 		if(n == BROKENREAD || length > 0){
4178193Smckusick 			unlink(tempfile);
4188193Smckusick 			return(-2);
4198193Smckusick 			}
4208193Smckusick 		sin = 1;
4218193Smckusick 		if(hd.hd_mchto != local){
4228193Smckusick 			diff = gettime() - otime;
4238193Smckusick 			if(diff < 1)diff = 1;	/* avoid dividing by 0 */
4248193Smckusick # ifndef NOFP
4258193Smckusick 			r = olength;
4268193Smckusick 			r = r/diff;
4278193Smckusick 			addtolog(remote,"^P(to %c, %ldb, %ldsec, %4.1fb/sec)\n",
4288193Smckusick 				hd.hd_mchto,olength,diff,r);
4298193Smckusick # else NOFP
4308193Smckusick 			addtolog(remote,"^P(to %c, %ldb, %ldsec)\n",
4318193Smckusick 				hd.hd_mchto,olength,diff);
4328193Smckusick # endif NOFP
4338193Smckusick 			dump.npass++;
4348193Smckusick 			dump.bytetot += olength;
4358193Smckusick 			dump.elaptot += diff;
4368193Smckusick 			while((pid = fork()) == -1)sleep(2);
4378193Smckusick 			if(pid == 0){
4388193Smckusick 				RENICE0();
4398193Smckusick #ifdef CCV7
4408193Smckusick 				/* make sure the spawned child has it's own
4418193Smckusick 					group process to avoid the nasty
4428193Smckusick 					"try again" message
4438193Smckusick 				*/
4448193Smckusick 				setpgrp();
4458193Smckusick #endif CCV7
4468193Smckusick 				execl(netcmd,"net","-x","-m",longname(hd.hd_mchto),
4478193Smckusick 					"-s",tempfile,0);
4488193Smckusick 				error("%s: %s",netcmd,sys_errlist[errno]);
4498193Smckusick 				exit(EX_UNAVAILABLE);
4508193Smckusick 				}
451*8510Scomay 			wait(&rcode);
4528193Smckusick 			unlink(tempfile);
4538193Smckusick 			rcode >>= 8;
4548193Smckusick 			if(rcode != 0)
455*8510Scomay 				error("pass-thru rcode %d", rcode);
4568193Smckusick 			debug("passthru to %c code %c rcode %d",
4578193Smckusick 				hd.hd_mchto,hd.hd_code,rcode);
4588193Smckusick 			return(1);
4598193Smckusick 			}
4608193Smckusick 		}
4618193Smckusick 	if(length > 0){error("file too short"); return(-1); }
4628193Smckusick 	rcvfinish = gettime();
4638193Smckusick 
4648193Smckusick 	while((pid = fork()) == -1)sleep(2);
4658193Smckusick 	if(pid > 0){
466*8510Scomay 		wait(&dummy);
4678193Smckusick 		return(1);	/* normal return */
4688193Smckusick 	}
4698193Smckusick 	/* this is a child, who will go ahead and execute the command */
4708193Smckusick 	/* running uid=0 at this point */
4718193Smckusick 	RENICE0();
4728193Smckusick 	/* nice(0 set back to 0 */
4738193Smckusick #ifdef CCV7
4748193Smckusick 	/* separate group process */
4758193Smckusick 	setpgrp();
4768193Smckusick #endif CCV7
4778193Smckusick 
4788193Smckusick 	while((pid = fork()) == -1)sleep(2);
4798193Smckusick 	if(pid != 0)exit(EX_OK);
4808193Smckusick 
4818193Smckusick 	/* child process which forks and waits */
4828193Smckusick 	mktemp(resfile);
4838193Smckusick 	while((pid = fork()) == -1)sleep(2);
4848193Smckusick 	if(pid == 0){
4858193Smckusick 		/* child */
4868193Smckusick 		strcpy(status.loginshell,Bsh);
4878193Smckusick 		frommach = hd.hd_mchfrom;
4888193Smckusick 		n = check(&hd,(hd.hd_code == 'q'));
4898193Smckusick 		if(!n)errormsg(TRUE,&hd,NULL,
4908193Smckusick 			"Bad remote login/password '%s'",hd.hd_snto);
4918193Smckusick 		temp = fopen(resfile,"w");
4928193Smckusick 		if(temp == NULL)
4938193Smckusick 			errormsg(TRUE,&hd,NULL,
4948193Smckusick 			"Create file %s: %s",resfile,sys_errlist[errno]);
4958193Smckusick 		fclose(temp);
4968193Smckusick 		chmod(resfile,0600);
4978193Smckusick 		mchown(resfile,status.muid,status.mgid);
4988193Smckusick 		if(sin)
4998193Smckusick 			mchown(tempfile,status.muid,status.mgid);
5008193Smckusick 		else tempfile[0] = 0;
5018193Smckusick 		setgid(status.mgid);
5028193Smckusick 		setuid(status.muid);
5038193Smckusick 		/* after this point our gid, uid is the target user's */
5048193Smckusick 		excmd(&hd,resfile,tempfile);
5058193Smckusick 	}
5068193Smckusick 	/* parent */
507*8510Scomay 	wait(&rcode);
5088193Smckusick 	rcode = (((rcode&077400) >>8) &0177);
5098193Smckusick 	/*
5108193Smckusick 	fclose(stdin);
5118193Smckusick 	fclose(stdout);
5128193Smckusick 	fclose(stderr);
5138193Smckusick 	*/
5148193Smckusick 	if(sin)unlink(tempfile);
5158193Smckusick 	/*
5168193Smckusick 	   now send something back to the sender
5178193Smckusick 	   unless this was a response (file or message)
5188193Smckusick 	*/
5198193Smckusick 	if((hd.hd_code == 'q' || hd.hd_code == 'y')
5208193Smckusick 	&& (hd.hd_srespfile[0] || !hd.hd_fnonotify))
5218193Smckusick 		sndresponse(&hd,rcode);
5228193Smckusick 	unlink(resfile);
5238193Smckusick 	s = ctime(&rcvfinish);
5248193Smckusick 	s += 4;
5258193Smckusick 	s[strlen(s) -8] = 0;
5268193Smckusick 	diff = rcvfinish - otime;
5278193Smckusick 	if(diff < 1)diff = 1;		/* avoid dividing by zero */
5288193Smckusick 	dump.bytetot += olength;
5298193Smckusick 	dump.elaptot += diff;
5308193Smckusick 	sprintf(buf,"%s rcv  %c:%-8s (%s)",
5318193Smckusick 		s,hd.hd_mchfrom,hd.hd_snfrom,hd.hd_snto);
5328193Smckusick 	addtolog(remote,"%s C: %s\n",buf,hd.hd_scmdvirt);
5338193Smckusick 	addtopublic("%s R: %d C: %s\n",buf,rcode,hd.hd_scmdvirt);
5348193Smckusick 	nt = rcvfinish - hd.hd_ltimesent;
5358193Smckusick 	buf[0] = 0;
5368193Smckusick 	if(nt > 0L)sprintf(buf," took (%s)",comptime(nt));
5378193Smckusick # ifndef NOFP
5388193Smckusick 	r = olength;
5398193Smckusick 	r = r/diff;
5408193Smckusick 	addtolog(remote,"\t\tR: %d%s %ldb %ldsec %4.1fb/sec\n",
5418193Smckusick 		rcode,buf,olength,diff,r);
5428193Smckusick 	r = dump.braw;
5438193Smckusick 	r = r/diff;
5448193Smckusick 	addtolog(remote,"\t\t%4.1frb/sec %4.1f%% use\n",r,(r/linechars())*100L);
5458193Smckusick # else NOFP
5468193Smckusick 	addtolog(remote,"\t\tR: %d%s %ldb %ldsec\n",
5478193Smckusick 		rcode,buf,olength,diff);
5488193Smckusick # endif NOFP
5498193Smckusick 	exit(EX_OK);
5508193Smckusick 	/*UNREACHED*/
5518193Smckusick 	}
linechars()5528193Smckusick long linechars(){
5538193Smckusick 	if(netd.dp_inspeed == 13)return(960L);
5548193Smckusick 	else return(120L);
5558193Smckusick 	}
5568193Smckusick /*
5578193Smckusick 	execute the user's command
5588193Smckusick 	this procedure is executed with uid, gid of the user
5598193Smckusick */
excmd(phd,tempresfile,tempinfile)5608193Smckusick excmd(phd,tempresfile,tempinfile)
5618193Smckusick 	register struct header *phd;
5628193Smckusick 	char *tempresfile, *tempinfile;
5638193Smckusick {
5648193Smckusick 	FILE *fd;
5658193Smckusick 	int i, uid;
5668193Smckusick 	register char *s, c;
5678193Smckusick 
5688193Smckusick 	uid = getuid();
5698193Smckusick 	uid = uidmask(uid);
5708193Smckusick 	status.muid = uidmask(status.muid);
5718193Smckusick 	if(uid != status.muid)error("setuid fails");
5728193Smckusick 	debug("uid: %u, gid: %u\n",uid,status.mgid);
5738193Smckusick 	/* check for allowed root commands, for security reasons */
5748193Smckusick 	if(uid == SUPERUSER){
5758193Smckusick 		s = phd->hd_scmdact;
5768193Smckusick 		while(*s && *s != ' ')s++;
5778193Smckusick 		c = *s;
5788193Smckusick 		*s = 0;
5798193Smckusick 		/* these are the only commands root may execute */
5808193Smckusick 		if(strcmp(phd->hd_scmdact,"cat")            	!= 0
5818193Smckusick 		&& strcmp(phd->hd_scmdact,MWRITECMD)        	!= 0
5828193Smckusick 		&& strcmp(phd->hd_scmdact,"/bin/cat")       	!= 0
5838193Smckusick 		&& strcmp(phd->hd_scmdact,"netrm")          	!= 0
5848193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/lib/tq")    	!= 0
5858193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/cc/lib/tq") 	!= 0
5868193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/lib/rtrrm") 	!= 0
5878193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/cc/lib/rtrrm")	!= 0
5888193Smckusick 		&& strcmp(phd->hd_scmdact,"lpr")            	!= 0)
5898193Smckusick 			errormsg(TRUE,phd,tempresfile,
5908193Smckusick 				"Not allowed to execute '%s' as root",
5918193Smckusick 				phd->hd_scmdact);
5928193Smckusick 		*s = c;
5938193Smckusick 		}
5948193Smckusick 	if(chdir(status.dir) < 0)
5958193Smckusick 		errormsg(TRUE,phd,tempresfile,
5968193Smckusick 			"chdir %s: %s",status.dir,sys_errlist[errno]);
5978193Smckusick 	setenv(status.dir);	/* set up v7 environment */
5988193Smckusick 	if(tempinfile[0])mreopen(TRUE,phd,tempresfile,tempinfile,"r",stdin);
5998193Smckusick 	else if(phd->hd_sinfile[0])mreopen(TRUE,phd,tempresfile,phd->hd_sinfile,"r",stdin);
6008193Smckusick 	else mreopen(TRUE,phd,tempresfile,"/dev/null","r",stdin);
6018193Smckusick 	if(phd->hd_code == 's' && phd->hd_soutfile[0]){
6028193Smckusick 		if(stat(phd->hd_soutfile,&statbuf) < 0
6038193Smckusick 		   || getsize(&statbuf) != 0)
6048193Smckusick 			errormsg(FALSE,phd,tempresfile,"Bad result file '%s'",phd->hd_soutfile);
6058193Smckusick 		mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout);
6068193Smckusick 		}
6078193Smckusick 	else if(phd->hd_soutfile[0]){
6088193Smckusick 		fd = fopen(phd->hd_soutfile,"w");
6098193Smckusick 		if(fd == NULL)
6108193Smckusick 			errormsg(TRUE,phd,tempresfile,"Open file %s: %s",
6118193Smckusick 				phd->hd_soutfile,sys_errlist[errno]);
6128193Smckusick 		fclose(fd);
6138193Smckusick 		mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout);
6148193Smckusick 		}
6158193Smckusick 	else mreopen(TRUE,phd,tempresfile,tempresfile,"a",stdout);
6168193Smckusick 	debug("exec '%s'\n",phd->hd_scmdact);
6178193Smckusick 	if(debugflg == 0){
6188193Smckusick 		/* cheat */
6198193Smckusick 		close(2);
6208193Smckusick 		dup(1);
6218193Smckusick 		/*
6228193Smckusick 		mreopen(TRUE,phd,tempresfile,tempresfile,"a",stderr);
6238193Smckusick 		*/
6248193Smckusick 		}
6258193Smckusick 	for(i=3;i<15;i++)close(i);
6268193Smckusick 	if(strcmp(phd->hd_scmdact,"cat") == 0
6278193Smckusick 	|| strcmp(phd->hd_scmdact,"/bin/cat") == 0)excat();
6288193Smckusick 	do {
6298193Smckusick 		mexecl(status.loginshell,"sh","-c",phd->hd_scmdact,0);
6308193Smckusick 		sleep(2);
6318193Smckusick 		} while(errno == ETXTBSY);
6328193Smckusick 	perror(status.loginshell);
6338193Smckusick 	exit(EX_UNAVAILABLE);
6348193Smckusick }
6358193Smckusick /*
6368193Smckusick 	send back a response
6378193Smckusick 
6388193Smckusick 	if errormsg was called the resfile should be unlinked,
6398193Smckusick 	to avoid two messages being sent there
6408193Smckusick */
sndresponse(phd,rcode)6418193Smckusick sndresponse(phd,rcode)
6428193Smckusick unsigned rcode;
6438193Smckusick struct header *phd;
6448193Smckusick {
6458193Smckusick 	char cmdstr[BUFSIZ], buf[BUFSIZ];
6468193Smckusick 	int dummy;
6478193Smckusick 	long maxfile = MAXFILELARGE;
6488193Smckusick 	/* send response back if a response file
6498193Smckusick 	was given or if mail/write is allowed */
6508193Smckusick 	if(stat(resfile,&statbuf) < 0){
6518193Smckusick 		error("%s %s",resfile,sys_errlist[errno]);
6528193Smckusick 		return;
6538193Smckusick 		}
6548193Smckusick 	if(getsize(&statbuf) >= maxfile){
6558193Smckusick 		errormsg(TRUE,phd,"Result file too large - not sent");
6568193Smckusick 		return;
6578193Smckusick 		}
6588193Smckusick 	if(getsize(&statbuf) == 0){
6598193Smckusick 		/* response file specified, no output generated */
6608193Smckusick 		if(phd->hd_srespfile[0] != 0)return;
6618193Smckusick 		/* quiet option - no output and a rcode of 0 */
6628193Smckusick 		if(rcode == 0 && phd->hd_fquiet)return;
6638193Smckusick 	}
6648193Smckusick 	/* use both old and new mwrite parm lists */
6658193Smckusick 
6668193Smckusick 	if(phd->hd_srespfile[0])
6678193Smckusick 		sprintf(cmdstr,"-o %s cat",phd->hd_srespfile);
6688193Smckusick 	else sprintf(cmdstr,
6698193Smckusick "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -c \"'%s'\" -y %s -e %ld -r %d",
6708193Smckusick 	MWRITECMD, phd->hd_snfrom,phd->hd_sttyname,phd->hd_lttytime,
6718193Smckusick 	phd->hd_mchto,phd->hd_snto, phd->hd_scmdvirt,phd->hd_ltimesent-TIMEBASE,
6728193Smckusick 	phd->hd_addrfrom, phd->hd_addrto, phd->hd_lttytime,
6738193Smckusick 	phd->hd_scmdvirt, phd->hd_sttyname, phd->hd_ltimesent-TIMEBASE, rcode);
6748193Smckusick 
6758193Smckusick 	sprintf(buf,"%s -m%c -z -b -l %s -s %s -c response %s",
6768193Smckusick 		netcmd,phd->hd_mchfrom,phd->hd_snfrom,resfile,cmdstr);
6778193Smckusick 	dummy = system(buf);		/* execute command buf */
6788193Smckusick }
6798193Smckusick 
6808193Smckusick /*
6818193Smckusick 
6828193Smckusick 	excat
6838193Smckusick 	does nothing more than copy standard input to standard
6848193Smckusick 	output, like the cat command, but reports write errors.
6858193Smckusick 	Uses getc and putc rather than fwrite and fread because
6868193Smckusick 	the latter call getc and putc.
6878193Smckusick */
excat()6888193Smckusick excat(){
6898193Smckusick 	register int n;
6908193Smckusick 	char buf[BUFSIZ];
6918193Smckusick 
6928193Smckusick 	errno = 0;
6938193Smckusick 	while((n = read(0,buf,BUFSIZ)) > 0){
6948193Smckusick 		if(write(1,buf,n) != n){
6958193Smckusick 			perror("filecat: stdout");
6968193Smckusick 			exit(EX_OSFILE);
6978193Smckusick 			}
6988193Smckusick 		}
6998193Smckusick 	if(errno){
7008193Smckusick 		perror("filecat: stdin");
7018193Smckusick 		exit(EX_OSFILE);
7028193Smckusick 	}
7038193Smckusick 	exit(EX_OK);
7048193Smckusick }
7058193Smckusick /* returns errors for netrcv() */
readhd(phd)7068193Smckusick static readhd(phd)
7078193Smckusick register struct header *phd;
7088193Smckusick {
7098193Smckusick 	char cflag, sbuf[BUFSIZ], parmlist[PARMLIST], *cptr;
7108193Smckusick 	int i, code;
7118193Smckusick 	code = mgetc();
7128193Smckusick 	phd->hd_mchto = mgetc();
7138193Smckusick 	if(code != 'q' && code != 'y' && code != 'w' && code != 's'){
7148193Smckusick 		error("bad code");
7158193Smckusick 		return(-1);
7168193Smckusick 		}
7178193Smckusick 	phd->hd_code = code;
7188193Smckusick 	for(i = 0; i < MAXINX; i++)
7198193Smckusick 		if(phd->hd_mchto == inxtoch(i)) break;
7208193Smckusick 	if(i >= MAXINX){
7218193Smckusick 		error("bad phd->hd_mchto");
7228193Smckusick 		return(-1);
7238193Smckusick 		}
7248193Smckusick 	if(phd->hd_mchto != local)return(-3);	/* being forwarded through us */
7258193Smckusick 	phd->hd_mchfrom = mgetc();
7268193Smckusick 	phd->hd_vmajor = mgetc();
7278193Smckusick 	phd->hd_vminor = mgetc();
7288193Smckusick 	i = 0;
7298193Smckusick 	i += mgets(phd->hd_snto,NS);
7308193Smckusick 	i += mgets(phd->hd_spasswd,20);
7318193Smckusick 	i += mgets(phd->hd_sinfile,FNS);
7328193Smckusick 	i += mgets(phd->hd_soutfile,FNS);
7338193Smckusick 	i += mgets(phd->hd_srespfile,FNS);
7348193Smckusick 	i += mgets(phd->hd_snfrom,NS);
7358193Smckusick 
7368193Smckusick 	/* addrfrom is the person who sent this to us,
7378193Smckusick 	   addrto is the person who received the command, i.e.
7388193Smckusick 	   addrto is on this machine */
7398193Smckusick 	if(phd->hd_snfrom[0] == 0)strcpy(phd->hd_snfrom,"root");
7408193Smckusick 	sprintf(phd->hd_addrfrom,  "%s:%s",longname(phd->hd_mchfrom),phd->hd_snfrom);
7418193Smckusick 	sprintf(phd->hd_addrto,    "%s:%s",longname(phd->hd_mchto),phd->hd_snto);
7428193Smckusick 
7438193Smckusick 	i += mgets(phd->hd_sttyname,20);
7448193Smckusick 	if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx");
7458193Smckusick 	cflag = mgetc();
7468193Smckusick 	if(!phd->hd_mchfrom || !phd->hd_code || !cflag || !phd->hd_vmajor || !phd->hd_vminor){
7478193Smckusick 		error("mgetc fails");
7488193Smckusick 		return(-1);
7498193Smckusick 		}
7508193Smckusick 
7518193Smckusick 	cflag -= 'a';
7528193Smckusick 	phd->hd_fnonotify = (cflag & F_NONOTIFY);
7538193Smckusick 	phd->hd_fquiet = (cflag & F_QUIET);
7548193Smckusick 
7558193Smckusick 	phd->hd_vmajor -= 'a';
7568193Smckusick 	phd->hd_vminor -= 'a';
7578193Smckusick 
7588193Smckusick 	i += mgets(sbuf,BUFSIZ);
7598193Smckusick 	phd->hd_lttytime = 0;
7608193Smckusick 	sscanf(sbuf,"%lo",&phd->hd_lttytime);
7618193Smckusick 
7628193Smckusick 	i += mgets(parmlist,PARMLIST);
7638193Smckusick #ifdef CRN
7648193Smckusick 	cptr = parmlist;
7658193Smckusick 	while( *cptr != '(' )
7668193Smckusick 		cptr++;
7678193Smckusick 	*cptr = '\0';
7688193Smckusick 	strcpy( phd->hd_ijobno, parmlist );
7698193Smckusick 	*cptr = '(';
7708193Smckusick #else CRN
7718193Smckusick 	strcpy( phd->hd_ijobno, "XYZZ" );
7728193Smckusick #endif CRN
7738193Smckusick 	/* keep variable parameter list in crn slot */
7748193Smckusick 	parseparmlist(parmlist);
7758193Smckusick 
7768193Smckusick 	i += mgets(sbuf,BUFSIZ);		/* time sent */
7778193Smckusick 	sscanf(sbuf,"%ld",&phd->hd_ltimesent);
7788193Smckusick 	phd->hd_ltimesent += TIMEBASE;
7798193Smckusick 	i += mgetcmd(phd->hd_scmdact);
7808193Smckusick 	i += mgetcmd(phd->hd_scmdvirt);
7818193Smckusick 	if(i != 0){error("mgets fails"); return(-1);}
7828193Smckusick 	if(phd->hd_scmdvirt[0] == 0)strcpy(phd->hd_scmdvirt,phd->hd_scmdact);
7838193Smckusick 	return(0);
7848193Smckusick }
7858193Smckusick /*
7868193Smckusick    check() -- verify login name and password
7878193Smckusick    phd    = login,passwd
7888193Smckusick    fverify  = 1 if password must check
7898193Smckusick    Returns 1 if password is ok, 0 if not.
7908193Smckusick */
check(phd,fverify)7918193Smckusick check(phd,fverify)	/* 1 if OK, 0 if not */
7928193Smckusick register struct header *phd;
7938193Smckusick int fverify;
7948193Smckusick {
7958193Smckusick 	char *sencpasswd, *u, *nullstr = "";
7968193Smckusick 	struct passwd *pwd;
7978193Smckusick #ifdef CRN
7988193Smckusick 	struct gecos *gcos;
7998193Smckusick #endif CRN
8008193Smckusick 	if(phd->hd_snto[0] == 0)return(!fverify);
8018193Smckusick 	debug("check: phd->hd_snto = %s\n", phd->hd_snto );
8028193Smckusick 	if(!goodacctname(phd->hd_snto))return(!fverify);
8038193Smckusick 	pwd = getpwnam(phd->hd_snto);
8048193Smckusick 	debug("got pwd=%d, pwd->pw_passwd = %s\n",pwd, pwd->pw_passwd);
8058193Smckusick 	if(pwd == NULL)return(!fverify);
8068193Smckusick 	if(*phd->hd_spasswd)sencpasswd = crypt(phd->hd_spasswd,pwd->pw_passwd);
8078193Smckusick 	else sencpasswd = nullstr;
8088193Smckusick 	debug("check: passwd(rcvd)=%s, passwd(file) = %s, passwd(encrypt)=%s\n", phd->hd_spasswd, pwd->pw_passwd, sencpasswd );
8098193Smckusick 
8108193Smckusick 	status.muid = guid(pwd->pw_uid,pwd->pw_gid);
8118193Smckusick 	status.mgid = pwd->pw_gid;
8128193Smckusick #ifdef CRN
8138193Smckusick 	if( (gcos=pwgecos( pwd->pw_gecos )) == NULL )
8148193Smckusick 		strcpy( status.jobno, MAGICCRN );
8158193Smckusick 	else
8168193Smckusick 		strcpy( status.jobno, gcos->gc_crn );
8178193Smckusick #else CRN
8188193Smckusick 	strcpy( status.jobno, "XYZZ");
8198193Smckusick #endif CRN
8208193Smckusick 	strcpy(status.dir,pwd->pw_dir);
8218193Smckusick 	strcpy(status.loginshell,pwd->pw_shell);
8228193Smckusick 	u = status.loginshell;
8238193Smckusick 	if(u[0] == 0 || strcmp("/bin/sbash",u) == 0)strcpy(u,Bsh);
8248193Smckusick 
8258193Smckusick 	getpwdf(pwd);
8268193Smckusick 	/* ignore network passwd */
8278193Smckusick 	/* acct is not a pair, acct is not "network", passwd is incorrect,
8288193Smckusick 	and verification is requested => passwd not ok */
8298193Smckusick 	if(!facctpaircheck(phd) && strcmp(phd->hd_snto,"network") != 0
8308193Smckusick 	&& strcmp(pwd->pw_passwd,sencpasswd) != 0 && fverify)
8318193Smckusick 		return(0);
8328193Smckusick 	return(1);	/* otherwise passwd ok */
8338193Smckusick 	}
mread(b,n)8348193Smckusick mread(b,n)
8358193Smckusick   register int n; {
8368193Smckusick 	if(length <= 0)return(0);
8378193Smckusick 	if(length < n)n = length;
8388193Smckusick 	n = nread(b,n);
8398193Smckusick 	if(n != BROKENREAD)length -= n;
8408193Smckusick 	return(n);
8418193Smckusick 	}
mgetc()8428193Smckusick char mgetc(){			/* returns 0 if fail */
8438193Smckusick 	register char c;
8448193Smckusick 	register int n;
8458193Smckusick 	char buf[3];
8468193Smckusick 	if((n=nread(buf,3)) == BROKENREAD)return(0);
8478193Smckusick 	if(n != 3){error("bad read %d",n); return(0); }
8488193Smckusick 	c = buf[0];
8498193Smckusick 	if(buf[1] != ' ' && buf[1] != ':'){error("Bad char %c",buf[1]); return(0); }
8508193Smckusick 	length -= 3;
8518193Smckusick 	if(length < 0){error("length wrong2 %ld",length); return(0); }
8528193Smckusick 	return(c);
8538193Smckusick 	}
8548193Smckusick /* read in string over the network wire */
8558193Smckusick /* put string in s, max length is maxlen */
mgets(s,maxlen)8568193Smckusick mgets(s,maxlen)			/* returns 0 if ok, 1 if not */
8578193Smckusick   int maxlen;
8588193Smckusick   register char *s; {
8598193Smckusick 	register char *q;
8608193Smckusick 	register int n;
8618193Smckusick 	char c;
8628193Smckusick 	q = s;
8638193Smckusick 	for(;;) {
8648193Smckusick 		if((n=nread(&c,1)) == BROKENREAD){
8658193Smckusick 			*s = 0;
8668193Smckusick 			error("mgets %s",s);
8678193Smckusick 			return(1);
8688193Smckusick 			}
8698193Smckusick 		if(n == 0)break;
8708193Smckusick 		if(c == '\\'){
8718193Smckusick 			if((n=nread(&c,1)) == BROKENREAD){
8728193Smckusick 				*s = 0;
8738193Smckusick 				error("mgets %s",s);
8748193Smckusick 				return(1);
8758193Smckusick 				}
8768193Smckusick 			if(n == 0)break;
8778193Smckusick 			}
8788193Smckusick 		if(c == ' ')break;
8798193Smckusick 		if(maxlen-- > 0) *s++ = c;
8808193Smckusick 		}
8818193Smckusick 	*s = 0;
8828193Smckusick 	if(nread(&c,1) == BROKENREAD){
8838193Smckusick 		error("mgets %s",s);
8848193Smckusick 		return(1);
8858193Smckusick 		}
8868193Smckusick 	length -= (s - q + 2);
8878193Smckusick 	if(length < 0){error("length wrong1 %ld %s",length,q); return(-1); }
8888193Smckusick 	if(maxlen < 0)
8898193Smckusick 		error("mgets - string too long");
8908193Smckusick 	return(0);
8918193Smckusick 	}
mgetcmd(s)8928193Smckusick mgetcmd(s)			/* returns 0 if succeed, 1 otherwise */
8938193Smckusick   char *s; {
8948193Smckusick 	int i,n;
8958193Smckusick 	char c;
8968193Smckusick 	i = 0;
8978193Smckusick 	for(;;){
8988193Smckusick 		if((n=nread(&c,1)) == BROKENREAD){
8998193Smckusick 			s[i] = 0;
9008193Smckusick 			error("mgetcmd %s",s);
9018193Smckusick 			return(1);
9028193Smckusick 			}
9038193Smckusick 		if(n <= 0 || c == '\n')break;
9048193Smckusick 		if(c == '\\'){
9058193Smckusick 			if(nread(&c,1) == BROKENREAD){
9068193Smckusick 				s[i] = 0;
9078193Smckusick 				error("mgetcmd %s",s);
9088193Smckusick 				return(1);
9098193Smckusick 				}
9108193Smckusick 			length--;
9118193Smckusick 			}
9128193Smckusick 		s[i++] = c;
9138193Smckusick 		length--;
9148193Smckusick 		}
9158193Smckusick 	s[i] = 0;
9168193Smckusick 	length--;
9178193Smckusick 	return(0);
9188193Smckusick 	}
increment(s)9198193Smckusick increment(s)
9208193Smckusick  char *s; {
9218193Smckusick 	int i;
9228193Smckusick 	char *p;
9238193Smckusick 	i = strlen(s) - 1;
9248193Smckusick 	while(s[i] == '9')i--;
9258193Smckusick 	if(s[i] < '0' || s[i] > '9'){
9268193Smckusick 		p = s+i+1;
9278193Smckusick 		while(*p)*p++ = '0';
9288193Smckusick 		return;
9298193Smckusick 		}
9308193Smckusick 	(s[i])++;
9318193Smckusick 	i++;
9328193Smckusick 	while(s[i])s[i++] = '0';
9338193Smckusick 	return;
9348193Smckusick 	}
9358193Smckusick /* gather 24-hour stats and  mail to STATADDR */
9368193Smckusick /* should also gather stats on # error msgs */
dumpit(currt)9378193Smckusick dumpit(currt)
9388193Smckusick   long currt; {
9398193Smckusick 	register struct dumpstruc *p = &dump;
9408193Smckusick 	register int ntot;
9418193Smckusick 	long elapt;
9428193Smckusick 	double cputime,utime,stime,bs,rawbs;
9438193Smckusick 	char *sstartt;
9448193Smckusick 	FILE *fdm;
9458193Smckusick 	char froma[30];
9468193Smckusick 	struct tms tbf;
9478193Smckusick 
9488193Smckusick 	/* if STATADDR is a file, the mail program this call will
9498193Smckusick 	   ultimately execute must be able to deal with it,
9508193Smckusick 	   and the remote mail program must be able to write on the
9518193Smckusick 	   file, i.e. mode 666 */
9528193Smckusick 	sprintf(froma,"%s=>",longname(local));
9538193Smckusick 	strcat(froma,longname(remote));
9548193Smckusick 	fdm = mailopen(STATADDR,froma,1,0);
9558193Smckusick 	if(fdm == NULL)return;
9568193Smckusick 
9578193Smckusick 	/* calculate times */
9588193Smckusick 	elapt = currt - dump.longtime;
9598193Smckusick 	ntot = p->nnetcp + p->nnetmail + p->nsmail + p->nnetlpr
9608193Smckusick 		+ p->nresp + p->nnet;
9618193Smckusick 	sstartt = ctime(&dump.longtime) + 4;
9628193Smckusick 	sstartt[strlen(sstartt) - 9] = 0;
9638193Smckusick 
9648193Smckusick 	times(&tbf);
9658193Smckusick # ifndef NOFP
9668193Smckusick 	utime = tbf.tms_utime + tbf.tms_cutime;
9678193Smckusick 	stime = tbf.tms_stime + tbf.tms_cstime;
9688193Smckusick 	cputime = utime + stime;
9698193Smckusick 	if(elapt > 0)cputime = (cputime/elapt) * 100.0;
9708193Smckusick 	else cputime = 0.0;
9718193Smckusick 	utime = utime/60.0;
9728193Smckusick 	stime = stime/60.0;
9738193Smckusick 	cputime = cputime/60.0;
9748193Smckusick 	bs = p->bytetot;
9758193Smckusick 	if(p->elaptot > 0)bs = bs /p->elaptot;
9768193Smckusick 	else bs = 0.0;
9778193Smckusick # endif NOFP
9788193Smckusick 
9798193Smckusick 	/* print out the statistics */
9808193Smckusick 	fprintf(fdm,"Subject: %s, %s, time %s\n",
9818193Smckusick 		froma,sstartt, comptime(elapt));
9828193Smckusick 	fprintf(fdm,"Command summary:\n");
9838193Smckusick 	fprintf(fdm,"\t# sent %d\t# pass_thru %d\t# rcv %d:\t# netcp %d\n",
9848193Smckusick 		p->nsend,p->npass,ntot,p->nnetcp);
9858193Smckusick 	fprintf(fdm,"\t# netlpr %d\t# netmail %d\t# sendbmail %d\t# resp %d\n",
9868193Smckusick 		p->nnetlpr,p->nnetmail,p->nsmail,p->nresp);
9878193Smckusick 	fprintf(fdm,"Protocol summary:\n");
9888193Smckusick 	fprintf(fdm,"\t# pk_sent %d\t# pk_rcv %d\t# b_sent %ld\t# b_rcv %ld\n",
9898193Smckusick 		p->npacksent,p->npackrcv,p->nbytesent, p->nbytercv);
9908193Smckusick 	fprintf(fdm,
9918193Smckusick 		"\t# send_fails %d\t# retrans %d\t# abn %d\t\t# cksum_errs %d\n",
9928193Smckusick 		p->nsendfail,p->nretrans, p->nabnormal,p->ncksum);
9938193Smckusick # ifndef NOFP
9948193Smckusick 	fprintf(fdm,"Load:\tuser %4.1f\tsys %4.1f\tpct %5.2f\trate %6.1f\n",
9958193Smckusick 		utime,stime,cputime,bs);
9968193Smckusick 	rawbs = p->brawtot*100L;
9978193Smckusick 	rawbs = rawbs / linechars();
9988193Smckusick 	fprintf(fdm,"\trawbytes %ld\tuse %4.1f\n", p->brawtot,rawbs);
9998193Smckusick # endif NOFP
10008193Smckusick 	mailclose(fdm);
10018193Smckusick 
10028193Smckusick 	/* reset counters */
10038193Smckusick 	p->nbytesent = p->nbytercv = p->elaptot = p->bytetot = 0L;
10048193Smckusick 	p->nretrans = p->nloop = p->nabnormal = p->ncksum = 0;
10058193Smckusick 	p->npacksent = p->npackrcv = p->nnetcp = p->nnetmail = 0;
10068193Smckusick 	p->nsmail = p->nnetlpr = p->nnet = p->npass = 0;
10078193Smckusick 	p->nsend = p->nsendfail = 0;
10088193Smckusick 	dump.longtime = currt;
10098193Smckusick 	}
10108193Smckusick /* returns 1 if n is ok, 0 if not */
goodacctname(n)10118193Smckusick goodacctname(n)
10128193Smckusick   char *n; {
10138193Smckusick 	int i;
10148193Smckusick 	i = -1;
10158193Smckusick 	while(btable[++i].bname)
10168193Smckusick 		if(strcmp(btable[i].bname,n) == 0 &&
10178193Smckusick 			local == btable[i].bmach)return(0);
10188193Smckusick 	return(1);
10198193Smckusick 	}
demask(s)10208193Smckusick demask(s)
10218193Smckusick   register char *s; {
10228193Smckusick /*
10238193Smckusick 	static char buf[20];
10248193Smckusick 	char skey[30];
10258193Smckusick 	makeuukey(skey,status.login,local);
10268193Smckusick 	strcpy(s,nbsdecrypt(s,skey,buf));
10278193Smckusick */
10288193Smckusick 	while(*s){
10298193Smckusick 		*s &= 0177;		/* strip quote bites */
10308193Smckusick 		*s++ ^= 040;		/* invert upper-lower */
10318193Smckusick 		}
10328193Smckusick 	}
10338193Smckusick /*VARARGS0*/
mreopen(fsendtofmach,phd,sfn,a,b,c)10348193Smckusick mreopen(fsendtofmach,phd,sfn,a,b,c){
10358193Smckusick /* simply handles errors by giving error msg */
10368193Smckusick 	if(freopen(a,b,c) == NULL)
10378193Smckusick 		errormsg(fsendtofmach,phd,sfn,"%s: %s",a,sys_errlist[errno]);
10388193Smckusick }
10398193Smckusick /*
10408193Smckusick 	addtopub(string, args)
10418193Smckusick 
10428193Smckusick 	add a message to the public logfile /usr/net/logfile.
10438193Smckusick 	note that the file must be writeable by everyone
10448193Smckusick 	if error messages from the netrcv subroutine
10458193Smckusick 	such as chdir errors are to be noticed.
10468193Smckusick */
10478193Smckusick /*VARARGS0*/
addtopublic(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n)10488193Smckusick addtopublic(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n)
10498193Smckusick char *s;
10508193Smckusick {
10518193Smckusick 	static FILE *log = NULL;
10528193Smckusick 	if(log == NULL){
10538193Smckusick 		if(stat(publogfile,&statbuf) < 0)return;
10548193Smckusick 		log = fopen(publogfile,"a");
10558193Smckusick 		if(log == NULL)return;
10568193Smckusick 		}
10578193Smckusick 	fseek(log,0L,2);
10588193Smckusick 	fprintf(log,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n);
10598193Smckusick 	fflush(log);
10608193Smckusick 	}
10618193Smckusick /* set up a dummy environment for v7 /bin/sh */
setenv(home)10628193Smckusick setenv(home)
10638193Smckusick   char *home; {
10648193Smckusick 	static char *env[3],benv[2][50];
10658193Smckusick 	env[0] = benv[0];
10668193Smckusick 	env[1] = benv[1];
10678193Smckusick #ifdef CCV7
10688193Smckusick 	strcpy( env[0], "PATH=:.:/usr/cc/bin:/usr/ucb/bin" );
10698193Smckusick #else CCV7
10708193Smckusick 	strcpy(env[0],"PATH=:/bin:/usr/bin");
10718193Smckusick #endif CCV7
10728193Smckusick 	sprintf(env[1],"HOME=%s",home);
10738193Smckusick 	env[2] = 0;
10748193Smckusick 	environ = env;
10758193Smckusick 	}
10768193Smckusick /*
10778193Smckusick 	errormsg(fsendtofmach,phd,sfn,"string",arg(s))
10788193Smckusick 
10798193Smckusick 	Sends error message to user.
10808193Smckusick 	If fsendtofmach=TRUE, send to phd->hd_mchfrom, otherwise
10818193Smckusick 	send to phd->hd_mchto.
10828193Smckusick 	Also, if error occured during return of a "response",
10838193Smckusick 	send to local machine.
10848193Smckusick 
10858193Smckusick 	Note that errormsg can be called by the netrcv subroutine
10868193Smckusick 	after the setuid() call to the specific user, so the
10878193Smckusick 	user must be able to get off an error msg back to him,
10888193Smckusick 	and to write in the two log files.
10898193Smckusick 	Can't use -w,-x,-y,-z for the net cmd because must be root for those.
10908193Smckusick 
10918193Smckusick 	If sfn != NULL, then unlink sfn before exiting.
10928193Smckusick */
10938193Smckusick /*VARARGS0*/
errormsg(fsendtofmach,phd,sfn,s,a,b,c,d,e,f,g,h)10948193Smckusick errormsg(fsendtofmach,phd,sfn,s,a,b,c,d,e,f,g,h)
10958193Smckusick char fsendtofmach;
10968193Smckusick struct header *phd;
10978193Smckusick char *sfn,*s;
10988193Smckusick {
10998193Smckusick 	int rcode;
11008193Smckusick 	char errstr[BUFSIZ], cmdstr[BUFSIZ], rcmd[BUFSIZ];
11018193Smckusick 	char toadd[FNS], fromadd[FNS], mchto, mchfrom;
11028193Smckusick 	char snto[FNS], snfrom[FNS];
11038193Smckusick 
11048193Smckusick 	if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx");
11058193Smckusick 	/* will send to toadd, from fromadd */
11068193Smckusick 	if(!fsendtofmach || strcmp(phd->hd_scmdvirt,"response") == 0){
11078193Smckusick 		/* send to tomach mach, thus send to toaddr. */
11088193Smckusick 		/* if this is an error during a response, send to local mach. */
11098193Smckusick 		strcpy(toadd,  phd->hd_addrto);
11108193Smckusick 		strcpy(fromadd,phd->hd_addrfrom);
11118193Smckusick 	}
11128193Smckusick 	else {		/* send to remote mach, thus send back to addrfrom*/
11138193Smckusick 		strcpy(toadd,  phd->hd_addrfrom);
11148193Smckusick 		strcpy(fromadd,phd->hd_addrto);
11158193Smckusick 	}
11168193Smckusick 	sprintf(errstr,"Error: ");
11178193Smckusick 	sprintf(cmdstr,s,a,b,c,d,e,f,g,h);
11188193Smckusick 	strcat(errstr,cmdstr);
11198193Smckusick 	strcat(errstr,"\n");
11208193Smckusick 	addtolog(remote,errstr);
11218193Smckusick 	addtopublic(errstr);
11228193Smckusick 
11238193Smckusick 	mchto =   MchSFromAddr(snto,toadd);
11248193Smckusick 	mchfrom = MchSFromAddr(snfrom,fromadd);
11258193Smckusick 
11268193Smckusick 	sprintf(rcmd,
11278193Smckusick "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -y %s -c \"'%s'\" -e %ld",
11288193Smckusick 	MWRITECMD, snto, phd->hd_sttyname, phd->hd_lttytime,
11298193Smckusick 	local, snfrom,phd->hd_scmdvirt, phd->hd_ltimesent-TIMEBASE,
11308193Smckusick 	toadd, fromadd, phd->hd_lttytime, phd->hd_sttyname, phd->hd_scmdvirt,
11318193Smckusick 	phd->hd_ltimesent-TIMEBASE);
11328193Smckusick 
11338193Smckusick 	if(mchto == local)
11348193Smckusick 		sprintf(cmdstr, "echo \"%s\" | %s", errstr,rcmd);
11358193Smckusick 	else
11368193Smckusick 		sprintf(cmdstr,
11378193Smckusick 		"echo \"%s\" | %s -m%c -b -c errormessage -l network - %s",
11388193Smckusick 			errstr,netcmd,mchto,rcmd);
11398193Smckusick 	rcode = system(cmdstr);
11408193Smckusick 	debug( "errormsg: cmdstr = %s\n", cmdstr );
11418193Smckusick 	debug( "errormsg: rcode = %d\n", rcode );
11428193Smckusick 	if(sfn != NULL)unlink(sfn);
11438193Smckusick 	exit(EX_USAGE);
11448193Smckusick 	}
handlekill()11458193Smckusick handlekill(){	/* SIGTERM signal */
11468193Smckusick 	long t;
11478193Smckusick 	/*
11488193Smckusick 	t = gettime();
11498193Smckusick 	dumpit(t);
11508193Smckusick 	*/
11518193Smckusick # ifdef NETLDISC
11528193Smckusick 	/* turn off net line discipline if possible */
11538193Smckusick 	netd.dp_linedis = 0;
11548193Smckusick 	ioctl(netd.dp_linefd,TIOCSETD,&netd.dp_linedis);
11558193Smckusick 	close(netd.dp_linefd);
11568193Smckusick 	printf("Network line discipline turned off.\n");
11578193Smckusick # endif NETLDISC
11588193Smckusick 	exit(EX_OK);	/* kill myself */
11598193Smckusick 	}
11608193Smckusick 
11618193Smckusick /* check a request to see if it is an acct pair */
11628193Smckusick /* returns 1 if it is, 0 if not */
facctpaircheck(phd)11638193Smckusick static facctpaircheck(phd)
11648193Smckusick register struct header *phd;
11658193Smckusick {
11668193Smckusick 	return(0);
11678193Smckusick }
11688193Smckusick 
1169