xref: /csrg-svn/old/berknet/netdaemon.c (revision 8193)
1*8193Smckusick static char sccsid[] = "@(#)netdaemon.c	4.1	(Berkeley)	09/12/82";
2*8193Smckusick 
3*8193Smckusick /* sccs id variable */
4*8193Smckusick static char *netdaemon_sid = "@(#)netdaemon.c	1.10";
5*8193Smckusick 
6*8193Smckusick /*
7*8193Smckusick 
8*8193Smckusick 	The daemon program that runs the network.
9*8193Smckusick 
10*8193Smckusick Usage:
11*8193Smckusick 	netdaemon -m mach [-r readfd] [-w writefd] [-d] [-h]
12*8193Smckusick 		[-os] [-or] [-ou num] [-p len] [-8] [-l]
13*8193Smckusick 
14*8193Smckusick Must be started by root.
15*8193Smckusick Options:
16*8193Smckusick 	-d		turn debugging on
17*8193Smckusick 	-h		use high-speed link (not implemented yet)
18*8193Smckusick 	-l		don't use net line discipline, even if available
19*8193Smckusick 	-m mach		remote machine is mach (required)
20*8193Smckusick 	-os		only send
21*8193Smckusick 	-or		only receive
22*8193Smckusick 	-ou num		only send things with uid = num
23*8193Smckusick 	-p num		length of packet
24*8193Smckusick 	-r num		if simulute w/pipes, read from num
25*8193Smckusick 	-w num		if simulate w/pipes, write on num
26*8193Smckusick */
27*8193Smckusick 
28*8193Smckusick # include "defs.h"
29*8193Smckusick /* take a time, adjust to be in PST, and divide by no of secs in a day */
30*8193Smckusick /* adjust by 10 mins, and day is considered to begin at 3AM */
31*8193Smckusick /* (6*3600 = 21600) + 17400 = 39000 */
32*8193Smckusick /* number of seconds in a day, usually 86400L */
33*8193Smckusick # define nsecday 86400L
34*8193Smckusick /* number of days since time began */
35*8193Smckusick # define numdays(S) ((S - 39000L)/nsecday)
36*8193Smckusick /* set my priority to normal */
37*8193Smckusick # define RENICE0() { if (getuid() == 0) { nice(-40); nice(20); nice(0); } }
38*8193Smckusick 
39*8193Smckusick /* global variables */
40*8193Smckusick extern char **environ;
41*8193Smckusick struct dumpstruc dump;
42*8193Smckusick struct bstruct btable[];
43*8193Smckusick struct daemonparms netd;
44*8193Smckusick struct userinfo status;
45*8193Smckusick 
46*8193Smckusick /* local variables */
47*8193Smckusick static long length;
48*8193Smckusick static FILE *dir;
49*8193Smckusick /* static char sheader[] = 		"ABCDE"; */
50*8193Smckusick static char tempfile[]= 	TEMPFILE;
51*8193Smckusick static char publogfile[]=  	PUBLOGFILE;
52*8193Smckusick static struct stat statbuf;
53*8193Smckusick static struct direct dirbuf;
54*8193Smckusick int handlekill();
55*8193Smckusick static char frommach;
56*8193Smckusick long linechars();
57*8193Smckusick 
58*8193Smckusick main(argc,argv)
59*8193Smckusick   char **argv; {
60*8193Smckusick 	register int i;
61*8193Smckusick 	long ltime,t;
62*8193Smckusick 	char buf[100];
63*8193Smckusick 
64*8193Smckusick 	nice(-1);
65*8193Smckusick 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
66*8193Smckusick 		signal(SIGHUP, handlekill);
67*8193Smckusick 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
68*8193Smckusick 		signal(SIGQUIT, handlekill);
69*8193Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
70*8193Smckusick 		signal(SIGINT, handlekill);
71*8193Smckusick 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
72*8193Smckusick 		signal(SIGTERM, handlekill);
73*8193Smckusick 	debugflg = DBV;
74*8193Smckusick 	setupdaemon(argc,argv);
75*8193Smckusick 	/* now running alone as a daemon */
76*8193Smckusick 		/*
77*8193Smckusick 		for(i=0; i<15; i++)close(i);
78*8193Smckusick 		signal(SIGHUP,SIG_IGN);
79*8193Smckusick 		signal(SIGQUIT,SIG_IGN);
80*8193Smckusick 		signal(SIGINT,SIG_IGN);
81*8193Smckusick 		*/
82*8193Smckusick 	/* set the umask to a reasonable value */
83*8193Smckusick 	umask( 022 );
84*8193Smckusick 	senddir[strlen(senddir)-1] = remote;		/* choose dir */
85*8193Smckusick 	if(chdir(senddir) < 0){
86*8193Smckusick 		perror(senddir);
87*8193Smckusick 		exit(EX_OSFILE);
88*8193Smckusick 		}
89*8193Smckusick 	dir = fopen(senddir,"r");
90*8193Smckusick 	if(dir == NULL){
91*8193Smckusick 		perror(senddir);
92*8193Smckusick 		exit(EX_OSFILE);
93*8193Smckusick 		}
94*8193Smckusick 	mktemp(tempfile);
95*8193Smckusick 	tempfile[strlen(tempfile) - 7] = remote;
96*8193Smckusick 	ltime = gettime();
97*8193Smckusick 	if(ltime == 0L)
98*8193Smckusick 		fprintf(stderr,"The network says 'The clock is set wrong.'\n");
99*8193Smckusick 	sprintf(buf,"net restarted to %s %d %s",longname(remote),
100*8193Smckusick 		getpid(),ctime(&ltime));
101*8193Smckusick 	dump.longtime = ltime;
102*8193Smckusick 	dump.lastndays = numdays(ltime);
103*8193Smckusick 	addtolog(remote,buf);
104*8193Smckusick 	addtopublic(buf);
105*8193Smckusick 	fprintf(stderr,buf);
106*8193Smckusick 	if(!debugflg)fclose(stderr);
107*8193Smckusick 	sendpurge();
108*8193Smckusick 	mainloop();
109*8193Smckusick 	/* never returns */
110*8193Smckusick }
111*8193Smckusick /* the main loop of the daemon, alternatively rcv then send, if poss.*/
112*8193Smckusick mainloop(){
113*8193Smckusick 	register int i;
114*8193Smckusick 
115*8193Smckusick 	for(;;){	/* begin reading file */
116*8193Smckusick 		debug("daemon %c %d\n",remote,getpid());
117*8193Smckusick 		/* first receive */
118*8193Smckusick 		if(netd.dp_sndorcv >= 0){	/* if we can receive */
119*8193Smckusick 			i = netrcv();
120*8193Smckusick 			if(i == -1)dump.nabnormal++;
121*8193Smckusick 		}
122*8193Smckusick 		/* now look to send */
123*8193Smckusick 		if(netd.dp_sndorcv <= 0)	/* if we can send */
124*8193Smckusick 			netsend();
125*8193Smckusick 		/* print out statistics if the right time */
126*8193Smckusick 		printstat();
127*8193Smckusick 		dump.nloop++;
128*8193Smckusick 	}
129*8193Smckusick }
130*8193Smckusick 	/* this code is a little strange because some machines
131*8193Smckusick 	   seem to have trouble having the date set, and time()
132*8193Smckusick 	   returns 0 until somebody remembers to set the date */
133*8193Smckusick printstat(){
134*8193Smckusick 	long thisndays, thistime;
135*8193Smckusick 	thistime = gettime();
136*8193Smckusick 	thisndays = numdays(thistime);
137*8193Smckusick 	if(dump.longtime == 0L){
138*8193Smckusick 		dump.longtime = thistime;
139*8193Smckusick 		dump.lastndays = thisndays;
140*8193Smckusick 		return;
141*8193Smckusick 		}
142*8193Smckusick 	if(thisndays == dump.lastndays + 1L) dumpit(thistime);
143*8193Smckusick 	dump.lastndays = thisndays;
144*8193Smckusick }
145*8193Smckusick /* look for files to send */
146*8193Smckusick netsend(){
147*8193Smckusick 	static long lasttime = 0;
148*8193Smckusick 	static char nleft = 1;
149*8193Smckusick 	long lFileLen,diff;
150*8193Smckusick 	double drate;
151*8193Smckusick 	register unsigned uid,uidBest;
152*8193Smckusick 	char *sdate,*sn,*swait;
153*8193Smckusick 	long ot,nt,filesize;
154*8193Smckusick 	register int i;
155*8193Smckusick 	char stemp[20];
156*8193Smckusick 	static char jname[FNS];
157*8193Smckusick 
158*8193Smckusick 	debug("ck send");
159*8193Smckusick 	if(stat(senddir,&statbuf) < 0){
160*8193Smckusick 		error("%s %s",senddir,sys_errlist[errno]);
161*8193Smckusick 		return;
162*8193Smckusick 		}
163*8193Smckusick 	if(statbuf.st_mtime == lasttime && nleft == 0)return;	/* no need to search */
164*8193Smckusick 	lasttime = statbuf.st_mtime;
165*8193Smckusick 	fseek(dir,0L,0);
166*8193Smckusick 	lFileLen = 10000000L;
167*8193Smckusick 	nleft = 0;
168*8193Smckusick 	while(fread(&dirbuf,1,sizeof dirbuf,dir) == sizeof dirbuf){
169*8193Smckusick 		if(dirbuf.d_ino == 0
170*8193Smckusick 		   || dirbuf.d_name[0] != 'c'
171*8193Smckusick 		   || dirbuf.d_name[1] != 'f'
172*8193Smckusick 		   || dirbuf.d_name[2] != remote
173*8193Smckusick 		   || stat(dirbuf.d_name,&statbuf) < 0
174*8193Smckusick 		   || statbuf.st_mode == 0)
175*8193Smckusick 			continue;
176*8193Smckusick 		dirbuf.d_name[0] = 'd';
177*8193Smckusick 		if(stat(dirbuf.d_name,&statbuf) < 0 || statbuf.st_mode == 0)
178*8193Smckusick 			continue;
179*8193Smckusick 		uid = guid(statbuf.st_uid,statbuf.st_gid);
180*8193Smckusick 		if(netd.dp_onlyuid != 0 && uid != netd.dp_onlyuid && uid != SUPERUSER
181*8193Smckusick 			&& uid != NUID)continue;
182*8193Smckusick 		nleft++;
183*8193Smckusick 		filesize = getsize(&statbuf);
184*8193Smckusick #ifndef DONTHOLDBIG
185*8193Smckusick 		if( (filesize > MAXDAYFILE) && day() ) {
186*8193Smckusick 			if( !debugflg )
187*8193Smckusick 				continue;
188*8193Smckusick 			else
189*8193Smckusick 				debug("sending large file %s\n", dirbuf.d_name );
190*8193Smckusick 		}
191*8193Smckusick #endif DONTHOLDBIG
192*8193Smckusick 		if(lFileLen > filesize){
193*8193Smckusick 			lFileLen = filesize;
194*8193Smckusick 			for(i=0; i<DIRSIZ; i++)
195*8193Smckusick 				jname[i] = dirbuf.d_name[i];
196*8193Smckusick 			uidBest = uid;
197*8193Smckusick 		}
198*8193Smckusick # ifdef MAXSENDQ
199*8193Smckusick 		if(nleft > MAXSENDQ)break;
200*8193Smckusick # endif MAXSENDQ
201*8193Smckusick 	}
202*8193Smckusick 	if(lFileLen == 10000000L)return;
203*8193Smckusick 	strcpy(stemp,jname);
204*8193Smckusick 	stemp[0] = 'c';
205*8193Smckusick 	sn = SnFromUid(uidBest);
206*8193Smckusick 	if(sn == NULL){
207*8193Smckusick 		addtolog(remote,"Unknown userid %d\n",uidBest);
208*8193Smckusick 		addtolog(remote,"Removing %s\n",stemp);
209*8193Smckusick 		unlink(stemp);
210*8193Smckusick 		return;
211*8193Smckusick 	}
212*8193Smckusick 	addtolog(remote,"^S %s %c: %s ",sn,remote,jname+2);
213*8193Smckusick 	ot = gettime();
214*8193Smckusick 	if(send(jname) == 0)return;
215*8193Smckusick 	nt = gettime();
216*8193Smckusick 	filesize = getsize(&statbuf);
217*8193Smckusick 	unlink(jname);
218*8193Smckusick 	unlink(stemp);
219*8193Smckusick 	diff = nt - ot;
220*8193Smckusick 	if(diff < 1)diff = 1;		/* avoid dividing by zero */
221*8193Smckusick 	sdate = ctime(&nt)+4;
222*8193Smckusick 	sdate[strlen(sdate) -9] = 0;
223*8193Smckusick 	swait = comptime(ot - statbuf.st_mtime);
224*8193Smckusick 	jname[3] = jname[2];
225*8193Smckusick # ifndef NOFP
226*8193Smckusick 	drate = (double)filesize / (double)diff;
227*8193Smckusick 	addtolog(remote,"^T%c(%s, %ldb, %ldsec, %4.1fb/sec, w %s)\n",
228*8193Smckusick 		remote,sdate,filesize, diff,drate, swait);
229*8193Smckusick # else NOFP
230*8193Smckusick 	addtolog(remote,"^T%c(%s, %ldb, %ldsec, w %s)\n",
231*8193Smckusick 		remote,sdate,filesize, diff,swait);
232*8193Smckusick # endif NOFP
233*8193Smckusick 	addtopublic("%s: sent %-8s to %s (%s, %ld b, wait %s)\n",
234*8193Smckusick 		sdate,sn,longname(remote),jname+3,filesize,swait);
235*8193Smckusick 	dump.nsend++;
236*8193Smckusick 	dump.bytetot += filesize;
237*8193Smckusick 	dump.elaptot += diff;
238*8193Smckusick 	}
239*8193Smckusick 
240*8193Smckusick /*
241*8193Smckusick    day() returns 1 if the time is between 6AM and 12PM
242*8193Smckusick */
243*8193Smckusick day()
244*8193Smckusick {
245*8193Smckusick 	int hour;
246*8193Smckusick 	long t;
247*8193Smckusick 	char *ctime();
248*8193Smckusick 
249*8193Smckusick 	time( &t );
250*8193Smckusick 	sscanf( ctime( &t ), "%*s%*s%*s%2d", &hour );
251*8193Smckusick 	if( (hour>=0) && (hour<6) )
252*8193Smckusick 		return( 0 );		/* night */
253*8193Smckusick 	else
254*8193Smckusick 		return( 1 );		/* day */
255*8193Smckusick }
256*8193Smckusick 
257*8193Smckusick send(jname)
258*8193Smckusick 	char *jname;
259*8193Smckusick {	/* push those bytes */
260*8193Smckusick 	/* returns 0 if send fails, 1 otherwise */
261*8193Smckusick 	register int n;
262*8193Smckusick 	int i;
263*8193Smckusick 	long lsize;
264*8193Smckusick 	char mbuf[20], buf[MAXNBUF];
265*8193Smckusick 	register char *p;
266*8193Smckusick 	register FILE *jfile;
267*8193Smckusick 
268*8193Smckusick 	debug("send %s",jname);
269*8193Smckusick 	if(stat(jname,&statbuf) < 0)goto sfail;
270*8193Smckusick 	lsize = getsize(&statbuf);
271*8193Smckusick 	if(lsize < MINSIZE){		/* all files are at least this long */
272*8193Smckusick 		unlink(jname);
273*8193Smckusick 		jname[0] = 'c';
274*8193Smckusick 		unlink(jname);
275*8193Smckusick 		return(1);
276*8193Smckusick 		}
277*8193Smckusick 	jfile = fopen(jname,"r");
278*8193Smckusick 	if(jfile == NULL)goto sfail;
279*8193Smckusick 	/*
280*8193Smckusick 	strcpy(mbuf,sheader);
281*8193Smckusick 	i = strlen(sheader);
282*8193Smckusick 	p = (char *)&lsize;
283*8193Smckusick 	lsize = fixuplong(lsize);
284*8193Smckusick 	mbuf[i] = *p++;
285*8193Smckusick 	mbuf[i+1] = *p++;
286*8193Smckusick 	mbuf[i+2] = *p++;
287*8193Smckusick 	mbuf[i+3] = *p++;
288*8193Smckusick 	i = i + 4;
289*8193Smckusick 	sendreset();
290*8193Smckusick 	*/
291*8193Smckusick 	initseqno();
292*8193Smckusick 	sprintf(mbuf,"|%08ld|",lsize);
293*8193Smckusick 	i = 10;
294*8193Smckusick 	if(xwrite(mbuf,i) == WRITEFAIL)goto bwrite;
295*8193Smckusick 	while((n=read(fileno(jfile),buf,MAXNBUF)) > 0)
296*8193Smckusick 		if(xwrite(buf,n) == WRITEFAIL)goto bwrite;
297*8193Smckusick 	fclose(jfile);
298*8193Smckusick 	debug("end send");
299*8193Smckusick 	return(1);
300*8193Smckusick bwrite:
301*8193Smckusick 	dump.nsendfail++;
302*8193Smckusick 	fclose(jfile);
303*8193Smckusick 	addtolog(remote,"^F%c\n",remote);
304*8193Smckusick 	return(0);
305*8193Smckusick sfail:
306*8193Smckusick 	error("%s: %s",jname,sys_errlist[errno]);
307*8193Smckusick 	dump.nsendfail++;
308*8193Smckusick 	return(0);
309*8193Smckusick 	}
310*8193Smckusick netrcv(){
311*8193Smckusick 	/* returns -2 in normal fail, -1 in abnormal fail, >= 0 otherwise */
312*8193Smckusick 	char sin;
313*8193Smckusick 	char mgetc(), *s;
314*8193Smckusick 	register int n;
315*8193Smckusick 	char c;
316*8193Smckusick 	int i, dummy, pid;
317*8193Smckusick 	unsigned rcode;
318*8193Smckusick 	long otime,olength,diff,rcvfinish,nt;
319*8193Smckusick 	double r;
320*8193Smckusick 	char hbuf[20], buf[MAXNBUF];
321*8193Smckusick 	register FILE *temp;
322*8193Smckusick 	static struct header hd;
323*8193Smckusick 
324*8193Smckusick 	initseqno();
325*8193Smckusick 	/*
326*8193Smckusick 	n = nread(hbuf,strlen(sheader));
327*8193Smckusick 	if(n == BROKENREAD)return(-2);
328*8193Smckusick 	if(n != strlen(sheader) || strcmp(sheader,hbuf) != 0){
329*8193Smckusick 		error("wrong head %d %s",n,hbuf);
330*8193Smckusick 		return(-1);
331*8193Smckusick 		}
332*8193Smckusick 	n = nread(&length,4);
333*8193Smckusick 	length = fixuplong(length);
334*8193Smckusick 	*/
335*8193Smckusick 	n = nread(hbuf,10);
336*8193Smckusick 	if(n == BROKENREAD)return(-2);
337*8193Smckusick 	if(n != 10){
338*8193Smckusick 		error("bad length nread %d",n);
339*8193Smckusick 		return(-1);
340*8193Smckusick 		}
341*8193Smckusick 	hbuf[10] = 0;
342*8193Smckusick 	if(hbuf[0] != '|' || hbuf[9] != '|'){
343*8193Smckusick 		error("poor format %s",hbuf);
344*8193Smckusick 		return(-1);
345*8193Smckusick 		}
346*8193Smckusick 	hbuf[9] = 0;
347*8193Smckusick 	length = atol(hbuf+1);
348*8193Smckusick 	if(length < 0 || length > 100000000L){
349*8193Smckusick 		error("bad length %ld",length);
350*8193Smckusick 		return(-1);
351*8193Smckusick 		}
352*8193Smckusick 	dump.braw = 4;
353*8193Smckusick 	olength = length;
354*8193Smckusick 	otime = gettime();
355*8193Smckusick 	debug("length = %ld\n",length);
356*8193Smckusick 
357*8193Smckusick /*
358*8193Smckusick 	begin parsing header
359*8193Smckusick 
360*8193Smckusick 	from local to remote (requests)
361*8193Smckusick 	code	net option	reason
362*8193Smckusick 	q			normal request
363*8193Smckusick 	y	-y		simply skips login check (used by netlpr)
364*8193Smckusick 
365*8193Smckusick 	from remote to local
366*8193Smckusick 	code	net option	reason
367*8193Smckusick 	w	-w		message to be written/mailed back
368*8193Smckusick 	s	-z		normal response
369*8193Smckusick */
370*8193Smckusick 
371*8193Smckusick 	i = readhd(&hd);
372*8193Smckusick 	if(i == -3)goto forw;			/* being forwarded thru us */
373*8193Smckusick 	if(i != 0)return(i);
374*8193Smckusick 
375*8193Smckusick 	strcpy(status.login, hd.hd_snto);
376*8193Smckusick 	strcpy(status.localname,hd.hd_snfrom);
377*8193Smckusick 
378*8193Smckusick 	demask(hd.hd_spasswd);
379*8193Smckusick 
380*8193Smckusick 	s = hd.hd_scmdvirt;
381*8193Smckusick 	while(*s && *s != ' ')s++;
382*8193Smckusick 	c = *s;
383*8193Smckusick 	*s = 0;
384*8193Smckusick 	if(strcmp(hd.hd_scmdvirt,"netlpr") == 0)dump.nnetlpr++;
385*8193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"netmail") == 0)dump.nnetmail++;
386*8193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"mail") == 0)dump.nsmail++;
387*8193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"netcp") == 0)dump.nnetcp++;
388*8193Smckusick 	else if(strcmp(hd.hd_scmdvirt,"response") == 0)dump.nresp++;
389*8193Smckusick 	else dump.nnet++;
390*8193Smckusick 	*s = c;
391*8193Smckusick 
392*8193Smckusick 	printhd(&hd);
393*8193Smckusick 
394*8193Smckusick 	/* any chars left are data */
395*8193Smckusick forw:
396*8193Smckusick 	sin = 0;
397*8193Smckusick 	if(length > 0){	/* make a temp input file */
398*8193Smckusick 		increment(tempfile);
399*8193Smckusick 		temp = fopen(tempfile,"w");
400*8193Smckusick 		if(temp == NULL){
401*8193Smckusick 			error("%s %s",tempfile,sys_errlist[errno]);
402*8193Smckusick 			return(-1);
403*8193Smckusick 			}
404*8193Smckusick 		chmod(tempfile,0600);
405*8193Smckusick 		if(hd.hd_mchto != local){
406*8193Smckusick 			fprintf(temp,"%c :%c :",hd.hd_code,hd.hd_mchto);
407*8193Smckusick 			fflush(temp);
408*8193Smckusick 		}
409*8193Smckusick 		/* this is the loop to read in all the data */
410*8193Smckusick 		while((n = mread(buf,MAXNBUF)) > 0)
411*8193Smckusick 			if(write(fileno(temp),buf,n) != n){
412*8193Smckusick 				error("%s %s",tempfile,sys_errlist[errno]);
413*8193Smckusick 				fclose(temp);
414*8193Smckusick 				unlink(tempfile);
415*8193Smckusick 				return(-1);
416*8193Smckusick 				};
417*8193Smckusick 		fclose(temp);
418*8193Smckusick 		if(n == BROKENREAD || length > 0){
419*8193Smckusick 			unlink(tempfile);
420*8193Smckusick 			return(-2);
421*8193Smckusick 			}
422*8193Smckusick 		sin = 1;
423*8193Smckusick 		if(hd.hd_mchto != local){
424*8193Smckusick 			diff = gettime() - otime;
425*8193Smckusick 			if(diff < 1)diff = 1;	/* avoid dividing by 0 */
426*8193Smckusick # ifndef NOFP
427*8193Smckusick 			r = olength;
428*8193Smckusick 			r = r/diff;
429*8193Smckusick 			addtolog(remote,"^P(to %c, %ldb, %ldsec, %4.1fb/sec)\n",
430*8193Smckusick 				hd.hd_mchto,olength,diff,r);
431*8193Smckusick # else NOFP
432*8193Smckusick 			addtolog(remote,"^P(to %c, %ldb, %ldsec)\n",
433*8193Smckusick 				hd.hd_mchto,olength,diff);
434*8193Smckusick # endif NOFP
435*8193Smckusick 			dump.npass++;
436*8193Smckusick 			dump.bytetot += olength;
437*8193Smckusick 			dump.elaptot += diff;
438*8193Smckusick 			while((pid = fork()) == -1)sleep(2);
439*8193Smckusick 			if(pid == 0){
440*8193Smckusick # ifndef V6
441*8193Smckusick 				RENICE0();
442*8193Smckusick # endif V6
443*8193Smckusick #ifdef CCV7
444*8193Smckusick 				/* make sure the spawned child has it's own
445*8193Smckusick 					group process to avoid the nasty
446*8193Smckusick 					"try again" message
447*8193Smckusick 				*/
448*8193Smckusick 				setpgrp();
449*8193Smckusick #endif CCV7
450*8193Smckusick 				execl(netcmd,"net","-x","-m",longname(hd.hd_mchto),
451*8193Smckusick 					"-s",tempfile,0);
452*8193Smckusick 				error("%s: %s",netcmd,sys_errlist[errno]);
453*8193Smckusick 				exit(EX_UNAVAILABLE);
454*8193Smckusick 				}
455*8193Smckusick 			wait(&rcode);
456*8193Smckusick 			unlink(tempfile);
457*8193Smckusick 			rcode >>= 8;
458*8193Smckusick 			if(rcode != 0)
459*8193Smckusick 				error("pass-thru rcode %d");
460*8193Smckusick 			debug("passthru to %c code %c rcode %d",
461*8193Smckusick 				hd.hd_mchto,hd.hd_code,rcode);
462*8193Smckusick 			return(1);
463*8193Smckusick 			}
464*8193Smckusick 		}
465*8193Smckusick 	if(length > 0){error("file too short"); return(-1); }
466*8193Smckusick 	rcvfinish = gettime();
467*8193Smckusick 
468*8193Smckusick 	while((pid = fork()) == -1)sleep(2);
469*8193Smckusick 	if(pid > 0){
470*8193Smckusick 		wait(&dummy);
471*8193Smckusick 		return(1);	/* normal return */
472*8193Smckusick 	}
473*8193Smckusick 	/* this is a child, who will go ahead and execute the command */
474*8193Smckusick 	/* running uid=0 at this point */
475*8193Smckusick # ifndef V6
476*8193Smckusick 	RENICE0();
477*8193Smckusick # endif V6
478*8193Smckusick 	/* nice(0 set back to 0 */
479*8193Smckusick #ifdef CCV7
480*8193Smckusick 	/* separate group process */
481*8193Smckusick 	setpgrp();
482*8193Smckusick #endif CCV7
483*8193Smckusick 
484*8193Smckusick 	while((pid = fork()) == -1)sleep(2);
485*8193Smckusick 	if(pid != 0)exit(EX_OK);
486*8193Smckusick 
487*8193Smckusick 	/* child process which forks and waits */
488*8193Smckusick 	mktemp(resfile);
489*8193Smckusick 	while((pid = fork()) == -1)sleep(2);
490*8193Smckusick 	if(pid == 0){
491*8193Smckusick 		/* child */
492*8193Smckusick 		strcpy(status.loginshell,Bsh);
493*8193Smckusick 		frommach = hd.hd_mchfrom;
494*8193Smckusick 		n = check(&hd,(hd.hd_code == 'q'));
495*8193Smckusick 		if(!n)errormsg(TRUE,&hd,NULL,
496*8193Smckusick 			"Bad remote login/password '%s'",hd.hd_snto);
497*8193Smckusick 		temp = fopen(resfile,"w");
498*8193Smckusick 		if(temp == NULL)
499*8193Smckusick 			errormsg(TRUE,&hd,NULL,
500*8193Smckusick 			"Create file %s: %s",resfile,sys_errlist[errno]);
501*8193Smckusick 		fclose(temp);
502*8193Smckusick 		chmod(resfile,0600);
503*8193Smckusick 		mchown(resfile,status.muid,status.mgid);
504*8193Smckusick 		if(sin)
505*8193Smckusick 			mchown(tempfile,status.muid,status.mgid);
506*8193Smckusick 		else tempfile[0] = 0;
507*8193Smckusick 		setgid(status.mgid);
508*8193Smckusick 		setuid(status.muid);
509*8193Smckusick 		/* after this point our gid, uid is the target user's */
510*8193Smckusick 		excmd(&hd,resfile,tempfile);
511*8193Smckusick 	}
512*8193Smckusick 	/* parent */
513*8193Smckusick 	wait(&rcode);
514*8193Smckusick 	rcode = (((rcode&077400) >>8) &0177);
515*8193Smckusick 	/*
516*8193Smckusick 	fclose(stdin);
517*8193Smckusick 	fclose(stdout);
518*8193Smckusick 	fclose(stderr);
519*8193Smckusick 	*/
520*8193Smckusick 	if(sin)unlink(tempfile);
521*8193Smckusick 	/*
522*8193Smckusick 	   now send something back to the sender
523*8193Smckusick 	   unless this was a response (file or message)
524*8193Smckusick 	*/
525*8193Smckusick 	if((hd.hd_code == 'q' || hd.hd_code == 'y')
526*8193Smckusick 	&& (hd.hd_srespfile[0] || !hd.hd_fnonotify))
527*8193Smckusick 		sndresponse(&hd,rcode);
528*8193Smckusick 	unlink(resfile);
529*8193Smckusick 	s = ctime(&rcvfinish);
530*8193Smckusick 	s += 4;
531*8193Smckusick 	s[strlen(s) -8] = 0;
532*8193Smckusick 	diff = rcvfinish - otime;
533*8193Smckusick 	if(diff < 1)diff = 1;		/* avoid dividing by zero */
534*8193Smckusick 	dump.bytetot += olength;
535*8193Smckusick 	dump.elaptot += diff;
536*8193Smckusick 	sprintf(buf,"%s rcv  %c:%-8s (%s)",
537*8193Smckusick 		s,hd.hd_mchfrom,hd.hd_snfrom,hd.hd_snto);
538*8193Smckusick 	addtolog(remote,"%s C: %s\n",buf,hd.hd_scmdvirt);
539*8193Smckusick 	addtopublic("%s R: %d C: %s\n",buf,rcode,hd.hd_scmdvirt);
540*8193Smckusick 	nt = rcvfinish - hd.hd_ltimesent;
541*8193Smckusick 	buf[0] = 0;
542*8193Smckusick 	if(nt > 0L)sprintf(buf," took (%s)",comptime(nt));
543*8193Smckusick # ifndef NOFP
544*8193Smckusick 	r = olength;
545*8193Smckusick 	r = r/diff;
546*8193Smckusick 	addtolog(remote,"\t\tR: %d%s %ldb %ldsec %4.1fb/sec\n",
547*8193Smckusick 		rcode,buf,olength,diff,r);
548*8193Smckusick 	r = dump.braw;
549*8193Smckusick 	r = r/diff;
550*8193Smckusick 	addtolog(remote,"\t\t%4.1frb/sec %4.1f%% use\n",r,(r/linechars())*100L);
551*8193Smckusick # else NOFP
552*8193Smckusick 	addtolog(remote,"\t\tR: %d%s %ldb %ldsec\n",
553*8193Smckusick 		rcode,buf,olength,diff);
554*8193Smckusick # endif NOFP
555*8193Smckusick 	exit(EX_OK);
556*8193Smckusick 	/*UNREACHED*/
557*8193Smckusick 	}
558*8193Smckusick long linechars(){
559*8193Smckusick 	if(netd.dp_inspeed == 13)return(960L);
560*8193Smckusick 	else return(120L);
561*8193Smckusick 	}
562*8193Smckusick /*
563*8193Smckusick 	execute the user's command
564*8193Smckusick 	this procedure is executed with uid, gid of the user
565*8193Smckusick */
566*8193Smckusick excmd(phd,tempresfile,tempinfile)
567*8193Smckusick 	register struct header *phd;
568*8193Smckusick 	char *tempresfile, *tempinfile;
569*8193Smckusick {
570*8193Smckusick 	FILE *fd;
571*8193Smckusick 	int i, uid;
572*8193Smckusick 	register char *s, c;
573*8193Smckusick 
574*8193Smckusick 	uid = getuid();
575*8193Smckusick 	uid = uidmask(uid);
576*8193Smckusick 	status.muid = uidmask(status.muid);
577*8193Smckusick 	if(uid != status.muid)error("setuid fails");
578*8193Smckusick 	debug("uid: %u, gid: %u\n",uid,status.mgid);
579*8193Smckusick 	/* check for allowed root commands, for security reasons */
580*8193Smckusick 	if(uid == SUPERUSER){
581*8193Smckusick 		s = phd->hd_scmdact;
582*8193Smckusick 		while(*s && *s != ' ')s++;
583*8193Smckusick 		c = *s;
584*8193Smckusick 		*s = 0;
585*8193Smckusick 		/* these are the only commands root may execute */
586*8193Smckusick 		if(strcmp(phd->hd_scmdact,"cat")            	!= 0
587*8193Smckusick 		&& strcmp(phd->hd_scmdact,MWRITECMD)        	!= 0
588*8193Smckusick 		&& strcmp(phd->hd_scmdact,"/bin/cat")       	!= 0
589*8193Smckusick 		&& strcmp(phd->hd_scmdact,"netrm")          	!= 0
590*8193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/lib/tq")    	!= 0
591*8193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/cc/lib/tq") 	!= 0
592*8193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/lib/rtrrm") 	!= 0
593*8193Smckusick 		&& strcmp(phd->hd_scmdact,"/usr/cc/lib/rtrrm")	!= 0
594*8193Smckusick 		&& strcmp(phd->hd_scmdact,"lpr")            	!= 0)
595*8193Smckusick 			errormsg(TRUE,phd,tempresfile,
596*8193Smckusick 				"Not allowed to execute '%s' as root",
597*8193Smckusick 				phd->hd_scmdact);
598*8193Smckusick 		*s = c;
599*8193Smckusick 		}
600*8193Smckusick 	if(chdir(status.dir) < 0)
601*8193Smckusick 		errormsg(TRUE,phd,tempresfile,
602*8193Smckusick 			"chdir %s: %s",status.dir,sys_errlist[errno]);
603*8193Smckusick 	setenv(status.dir);	/* set up v7 environment */
604*8193Smckusick 	if(tempinfile[0])mreopen(TRUE,phd,tempresfile,tempinfile,"r",stdin);
605*8193Smckusick 	else if(phd->hd_sinfile[0])mreopen(TRUE,phd,tempresfile,phd->hd_sinfile,"r",stdin);
606*8193Smckusick 	else mreopen(TRUE,phd,tempresfile,"/dev/null","r",stdin);
607*8193Smckusick 	if(phd->hd_code == 's' && phd->hd_soutfile[0]){
608*8193Smckusick 		if(stat(phd->hd_soutfile,&statbuf) < 0
609*8193Smckusick 		   || getsize(&statbuf) != 0)
610*8193Smckusick 			errormsg(FALSE,phd,tempresfile,"Bad result file '%s'",phd->hd_soutfile);
611*8193Smckusick 		mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout);
612*8193Smckusick 		}
613*8193Smckusick 	else if(phd->hd_soutfile[0]){
614*8193Smckusick 		fd = fopen(phd->hd_soutfile,"w");
615*8193Smckusick 		if(fd == NULL)
616*8193Smckusick 			errormsg(TRUE,phd,tempresfile,"Open file %s: %s",
617*8193Smckusick 				phd->hd_soutfile,sys_errlist[errno]);
618*8193Smckusick 		fclose(fd);
619*8193Smckusick 		mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout);
620*8193Smckusick 		}
621*8193Smckusick 	else mreopen(TRUE,phd,tempresfile,tempresfile,"a",stdout);
622*8193Smckusick 	debug("exec '%s'\n",phd->hd_scmdact);
623*8193Smckusick 	if(debugflg == 0){
624*8193Smckusick 		/* cheat */
625*8193Smckusick 		close(2);
626*8193Smckusick 		dup(1);
627*8193Smckusick 		/*
628*8193Smckusick 		mreopen(TRUE,phd,tempresfile,tempresfile,"a",stderr);
629*8193Smckusick 		*/
630*8193Smckusick 		}
631*8193Smckusick 	for(i=3;i<15;i++)close(i);
632*8193Smckusick 	if(strcmp(phd->hd_scmdact,"cat") == 0
633*8193Smckusick 	|| strcmp(phd->hd_scmdact,"/bin/cat") == 0)excat();
634*8193Smckusick 	do {
635*8193Smckusick 		mexecl(status.loginshell,"sh","-c",phd->hd_scmdact,0);
636*8193Smckusick 		sleep(2);
637*8193Smckusick 		} while(errno == ETXTBSY);
638*8193Smckusick 	perror(status.loginshell);
639*8193Smckusick 	exit(EX_UNAVAILABLE);
640*8193Smckusick }
641*8193Smckusick /*
642*8193Smckusick 	send back a response
643*8193Smckusick 
644*8193Smckusick 	if errormsg was called the resfile should be unlinked,
645*8193Smckusick 	to avoid two messages being sent there
646*8193Smckusick */
647*8193Smckusick sndresponse(phd,rcode)
648*8193Smckusick unsigned rcode;
649*8193Smckusick struct header *phd;
650*8193Smckusick {
651*8193Smckusick 	char cmdstr[BUFSIZ], buf[BUFSIZ];
652*8193Smckusick 	int dummy;
653*8193Smckusick 	long maxfile = MAXFILELARGE;
654*8193Smckusick 	/* send response back if a response file
655*8193Smckusick 	was given or if mail/write is allowed */
656*8193Smckusick 	if(stat(resfile,&statbuf) < 0){
657*8193Smckusick 		error("%s %s",resfile,sys_errlist[errno]);
658*8193Smckusick 		return;
659*8193Smckusick 		}
660*8193Smckusick 	if(getsize(&statbuf) >= maxfile){
661*8193Smckusick 		errormsg(TRUE,phd,"Result file too large - not sent");
662*8193Smckusick 		return;
663*8193Smckusick 		}
664*8193Smckusick 	if(getsize(&statbuf) == 0){
665*8193Smckusick 		/* response file specified, no output generated */
666*8193Smckusick 		if(phd->hd_srespfile[0] != 0)return;
667*8193Smckusick 		/* quiet option - no output and a rcode of 0 */
668*8193Smckusick 		if(rcode == 0 && phd->hd_fquiet)return;
669*8193Smckusick 	}
670*8193Smckusick 	/* use both old and new mwrite parm lists */
671*8193Smckusick 
672*8193Smckusick 	if(phd->hd_srespfile[0])
673*8193Smckusick 		sprintf(cmdstr,"-o %s cat",phd->hd_srespfile);
674*8193Smckusick 	else sprintf(cmdstr,
675*8193Smckusick "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -c \"'%s'\" -y %s -e %ld -r %d",
676*8193Smckusick 	MWRITECMD, phd->hd_snfrom,phd->hd_sttyname,phd->hd_lttytime,
677*8193Smckusick 	phd->hd_mchto,phd->hd_snto, phd->hd_scmdvirt,phd->hd_ltimesent-TIMEBASE,
678*8193Smckusick 	phd->hd_addrfrom, phd->hd_addrto, phd->hd_lttytime,
679*8193Smckusick 	phd->hd_scmdvirt, phd->hd_sttyname, phd->hd_ltimesent-TIMEBASE, rcode);
680*8193Smckusick 
681*8193Smckusick 	sprintf(buf,"%s -m%c -z -b -l %s -s %s -c response %s",
682*8193Smckusick 		netcmd,phd->hd_mchfrom,phd->hd_snfrom,resfile,cmdstr);
683*8193Smckusick 	dummy = system(buf);		/* execute command buf */
684*8193Smckusick }
685*8193Smckusick 
686*8193Smckusick /*
687*8193Smckusick 
688*8193Smckusick 	excat
689*8193Smckusick 	does nothing more than copy standard input to standard
690*8193Smckusick 	output, like the cat command, but reports write errors.
691*8193Smckusick 	Uses getc and putc rather than fwrite and fread because
692*8193Smckusick 	the latter call getc and putc.
693*8193Smckusick */
694*8193Smckusick excat(){
695*8193Smckusick 	register int n;
696*8193Smckusick 	char buf[BUFSIZ];
697*8193Smckusick 
698*8193Smckusick 	errno = 0;
699*8193Smckusick 	while((n = read(0,buf,BUFSIZ)) > 0){
700*8193Smckusick 		if(write(1,buf,n) != n){
701*8193Smckusick 			perror("filecat: stdout");
702*8193Smckusick 			exit(EX_OSFILE);
703*8193Smckusick 			}
704*8193Smckusick 		}
705*8193Smckusick 	if(errno){
706*8193Smckusick 		perror("filecat: stdin");
707*8193Smckusick 		exit(EX_OSFILE);
708*8193Smckusick 	}
709*8193Smckusick 	exit(EX_OK);
710*8193Smckusick }
711*8193Smckusick /* returns errors for netrcv() */
712*8193Smckusick static readhd(phd)
713*8193Smckusick register struct header *phd;
714*8193Smckusick {
715*8193Smckusick 	char cflag, sbuf[BUFSIZ], parmlist[PARMLIST], *cptr;
716*8193Smckusick 	int i, code;
717*8193Smckusick 	code = mgetc();
718*8193Smckusick 	phd->hd_mchto = mgetc();
719*8193Smckusick 	if(code != 'q' && code != 'y' && code != 'w' && code != 's'){
720*8193Smckusick 		error("bad code");
721*8193Smckusick 		return(-1);
722*8193Smckusick 		}
723*8193Smckusick 	phd->hd_code = code;
724*8193Smckusick 	for(i = 0; i < MAXINX; i++)
725*8193Smckusick 		if(phd->hd_mchto == inxtoch(i)) break;
726*8193Smckusick 	if(i >= MAXINX){
727*8193Smckusick 		error("bad phd->hd_mchto");
728*8193Smckusick 		return(-1);
729*8193Smckusick 		}
730*8193Smckusick 	if(phd->hd_mchto != local)return(-3);	/* being forwarded through us */
731*8193Smckusick 	phd->hd_mchfrom = mgetc();
732*8193Smckusick 	phd->hd_vmajor = mgetc();
733*8193Smckusick 	phd->hd_vminor = mgetc();
734*8193Smckusick 	i = 0;
735*8193Smckusick 	i += mgets(phd->hd_snto,NS);
736*8193Smckusick 	i += mgets(phd->hd_spasswd,20);
737*8193Smckusick 	i += mgets(phd->hd_sinfile,FNS);
738*8193Smckusick 	i += mgets(phd->hd_soutfile,FNS);
739*8193Smckusick 	i += mgets(phd->hd_srespfile,FNS);
740*8193Smckusick 	i += mgets(phd->hd_snfrom,NS);
741*8193Smckusick 
742*8193Smckusick 	/* addrfrom is the person who sent this to us,
743*8193Smckusick 	   addrto is the person who received the command, i.e.
744*8193Smckusick 	   addrto is on this machine */
745*8193Smckusick 	if(phd->hd_snfrom[0] == 0)strcpy(phd->hd_snfrom,"root");
746*8193Smckusick 	sprintf(phd->hd_addrfrom,  "%s:%s",longname(phd->hd_mchfrom),phd->hd_snfrom);
747*8193Smckusick 	sprintf(phd->hd_addrto,    "%s:%s",longname(phd->hd_mchto),phd->hd_snto);
748*8193Smckusick 
749*8193Smckusick 	i += mgets(phd->hd_sttyname,20);
750*8193Smckusick 	if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx");
751*8193Smckusick 	cflag = mgetc();
752*8193Smckusick 	if(!phd->hd_mchfrom || !phd->hd_code || !cflag || !phd->hd_vmajor || !phd->hd_vminor){
753*8193Smckusick 		error("mgetc fails");
754*8193Smckusick 		return(-1);
755*8193Smckusick 		}
756*8193Smckusick 
757*8193Smckusick 	cflag -= 'a';
758*8193Smckusick 	phd->hd_fnonotify = (cflag & F_NONOTIFY);
759*8193Smckusick 	phd->hd_fquiet = (cflag & F_QUIET);
760*8193Smckusick 
761*8193Smckusick 	phd->hd_vmajor -= 'a';
762*8193Smckusick 	phd->hd_vminor -= 'a';
763*8193Smckusick 
764*8193Smckusick 	i += mgets(sbuf,BUFSIZ);
765*8193Smckusick 	phd->hd_lttytime = 0;
766*8193Smckusick 	sscanf(sbuf,"%lo",&phd->hd_lttytime);
767*8193Smckusick 
768*8193Smckusick 	i += mgets(parmlist,PARMLIST);
769*8193Smckusick #ifdef CRN
770*8193Smckusick 	cptr = parmlist;
771*8193Smckusick 	while( *cptr != '(' )
772*8193Smckusick 		cptr++;
773*8193Smckusick 	*cptr = '\0';
774*8193Smckusick 	strcpy( phd->hd_ijobno, parmlist );
775*8193Smckusick 	*cptr = '(';
776*8193Smckusick #else CRN
777*8193Smckusick 	strcpy( phd->hd_ijobno, "XYZZ" );
778*8193Smckusick #endif CRN
779*8193Smckusick 	/* keep variable parameter list in crn slot */
780*8193Smckusick 	parseparmlist(parmlist);
781*8193Smckusick 
782*8193Smckusick 	i += mgets(sbuf,BUFSIZ);		/* time sent */
783*8193Smckusick 	sscanf(sbuf,"%ld",&phd->hd_ltimesent);
784*8193Smckusick 	phd->hd_ltimesent += TIMEBASE;
785*8193Smckusick 	i += mgetcmd(phd->hd_scmdact);
786*8193Smckusick 	i += mgetcmd(phd->hd_scmdvirt);
787*8193Smckusick 	if(i != 0){error("mgets fails"); return(-1);}
788*8193Smckusick 	if(phd->hd_scmdvirt[0] == 0)strcpy(phd->hd_scmdvirt,phd->hd_scmdact);
789*8193Smckusick 	return(0);
790*8193Smckusick }
791*8193Smckusick /*
792*8193Smckusick    check() -- verify login name and password
793*8193Smckusick    phd    = login,passwd
794*8193Smckusick    fverify  = 1 if password must check
795*8193Smckusick    Returns 1 if password is ok, 0 if not.
796*8193Smckusick */
797*8193Smckusick check(phd,fverify)	/* 1 if OK, 0 if not */
798*8193Smckusick register struct header *phd;
799*8193Smckusick int fverify;
800*8193Smckusick {
801*8193Smckusick 	char *sencpasswd, *u, *nullstr = "";
802*8193Smckusick 	struct passwd *pwd;
803*8193Smckusick #ifdef CRN
804*8193Smckusick 	struct gecos *gcos;
805*8193Smckusick #endif CRN
806*8193Smckusick 	if(phd->hd_snto[0] == 0)return(!fverify);
807*8193Smckusick 	debug("check: phd->hd_snto = %s\n", phd->hd_snto );
808*8193Smckusick 	if(!goodacctname(phd->hd_snto))return(!fverify);
809*8193Smckusick 	pwd = getpwnam(phd->hd_snto);
810*8193Smckusick 	debug("got pwd=%d, pwd->pw_passwd = %s\n",pwd, pwd->pw_passwd);
811*8193Smckusick 	if(pwd == NULL)return(!fverify);
812*8193Smckusick 	if(*phd->hd_spasswd)sencpasswd = crypt(phd->hd_spasswd,pwd->pw_passwd);
813*8193Smckusick 	else sencpasswd = nullstr;
814*8193Smckusick 	debug("check: passwd(rcvd)=%s, passwd(file) = %s, passwd(encrypt)=%s\n", phd->hd_spasswd, pwd->pw_passwd, sencpasswd );
815*8193Smckusick 
816*8193Smckusick 	status.muid = guid(pwd->pw_uid,pwd->pw_gid);
817*8193Smckusick 	status.mgid = pwd->pw_gid;
818*8193Smckusick #ifdef CRN
819*8193Smckusick 	if( (gcos=pwgecos( pwd->pw_gecos )) == NULL )
820*8193Smckusick 		strcpy( status.jobno, MAGICCRN );
821*8193Smckusick 	else
822*8193Smckusick 		strcpy( status.jobno, gcos->gc_crn );
823*8193Smckusick #else CRN
824*8193Smckusick 	strcpy( status.jobno, "XYZZ");
825*8193Smckusick #endif CRN
826*8193Smckusick 	strcpy(status.dir,pwd->pw_dir);
827*8193Smckusick 	strcpy(status.loginshell,pwd->pw_shell);
828*8193Smckusick 	u = status.loginshell;
829*8193Smckusick 	if(u[0] == 0 || strcmp("/bin/sbash",u) == 0)strcpy(u,Bsh);
830*8193Smckusick 
831*8193Smckusick 	getpwdf(pwd);
832*8193Smckusick 	/* ignore network passwd */
833*8193Smckusick 	/* acct is not a pair, acct is not "network", passwd is incorrect,
834*8193Smckusick 	and verification is requested => passwd not ok */
835*8193Smckusick 	if(!facctpaircheck(phd) && strcmp(phd->hd_snto,"network") != 0
836*8193Smckusick 	&& strcmp(pwd->pw_passwd,sencpasswd) != 0 && fverify)
837*8193Smckusick 		return(0);
838*8193Smckusick 	return(1);	/* otherwise passwd ok */
839*8193Smckusick 	}
840*8193Smckusick mread(b,n)
841*8193Smckusick   register int n; {
842*8193Smckusick 	if(length <= 0)return(0);
843*8193Smckusick 	if(length < n)n = length;
844*8193Smckusick 	n = nread(b,n);
845*8193Smckusick 	if(n != BROKENREAD)length -= n;
846*8193Smckusick 	return(n);
847*8193Smckusick 	}
848*8193Smckusick char mgetc(){			/* returns 0 if fail */
849*8193Smckusick 	register char c;
850*8193Smckusick 	register int n;
851*8193Smckusick 	char buf[3];
852*8193Smckusick 	if((n=nread(buf,3)) == BROKENREAD)return(0);
853*8193Smckusick 	if(n != 3){error("bad read %d",n); return(0); }
854*8193Smckusick 	c = buf[0];
855*8193Smckusick 	if(buf[1] != ' ' && buf[1] != ':'){error("Bad char %c",buf[1]); return(0); }
856*8193Smckusick 	length -= 3;
857*8193Smckusick 	if(length < 0){error("length wrong2 %ld",length); return(0); }
858*8193Smckusick 	return(c);
859*8193Smckusick 	}
860*8193Smckusick /* read in string over the network wire */
861*8193Smckusick /* put string in s, max length is maxlen */
862*8193Smckusick mgets(s,maxlen)			/* returns 0 if ok, 1 if not */
863*8193Smckusick   int maxlen;
864*8193Smckusick   register char *s; {
865*8193Smckusick 	register char *q;
866*8193Smckusick 	register int n;
867*8193Smckusick 	char c;
868*8193Smckusick 	q = s;
869*8193Smckusick 	for(;;) {
870*8193Smckusick 		if((n=nread(&c,1)) == BROKENREAD){
871*8193Smckusick 			*s = 0;
872*8193Smckusick 			error("mgets %s",s);
873*8193Smckusick 			return(1);
874*8193Smckusick 			}
875*8193Smckusick 		if(n == 0)break;
876*8193Smckusick 		if(c == '\\'){
877*8193Smckusick 			if((n=nread(&c,1)) == BROKENREAD){
878*8193Smckusick 				*s = 0;
879*8193Smckusick 				error("mgets %s",s);
880*8193Smckusick 				return(1);
881*8193Smckusick 				}
882*8193Smckusick 			if(n == 0)break;
883*8193Smckusick 			}
884*8193Smckusick 		if(c == ' ')break;
885*8193Smckusick 		if(maxlen-- > 0) *s++ = c;
886*8193Smckusick 		}
887*8193Smckusick 	*s = 0;
888*8193Smckusick 	if(nread(&c,1) == BROKENREAD){
889*8193Smckusick 		error("mgets %s",s);
890*8193Smckusick 		return(1);
891*8193Smckusick 		}
892*8193Smckusick 	length -= (s - q + 2);
893*8193Smckusick 	if(length < 0){error("length wrong1 %ld %s",length,q); return(-1); }
894*8193Smckusick 	if(maxlen < 0)
895*8193Smckusick 		error("mgets - string too long");
896*8193Smckusick 	return(0);
897*8193Smckusick 	}
898*8193Smckusick mgetcmd(s)			/* returns 0 if succeed, 1 otherwise */
899*8193Smckusick   char *s; {
900*8193Smckusick 	int i,n;
901*8193Smckusick 	char c;
902*8193Smckusick 	i = 0;
903*8193Smckusick 	for(;;){
904*8193Smckusick 		if((n=nread(&c,1)) == BROKENREAD){
905*8193Smckusick 			s[i] = 0;
906*8193Smckusick 			error("mgetcmd %s",s);
907*8193Smckusick 			return(1);
908*8193Smckusick 			}
909*8193Smckusick 		if(n <= 0 || c == '\n')break;
910*8193Smckusick 		if(c == '\\'){
911*8193Smckusick 			if(nread(&c,1) == BROKENREAD){
912*8193Smckusick 				s[i] = 0;
913*8193Smckusick 				error("mgetcmd %s",s);
914*8193Smckusick 				return(1);
915*8193Smckusick 				}
916*8193Smckusick 			length--;
917*8193Smckusick 			}
918*8193Smckusick 		s[i++] = c;
919*8193Smckusick 		length--;
920*8193Smckusick 		}
921*8193Smckusick 	s[i] = 0;
922*8193Smckusick 	length--;
923*8193Smckusick 	return(0);
924*8193Smckusick 	}
925*8193Smckusick increment(s)
926*8193Smckusick  char *s; {
927*8193Smckusick 	int i;
928*8193Smckusick 	char *p;
929*8193Smckusick 	i = strlen(s) - 1;
930*8193Smckusick 	while(s[i] == '9')i--;
931*8193Smckusick 	if(s[i] < '0' || s[i] > '9'){
932*8193Smckusick 		p = s+i+1;
933*8193Smckusick 		while(*p)*p++ = '0';
934*8193Smckusick 		return;
935*8193Smckusick 		}
936*8193Smckusick 	(s[i])++;
937*8193Smckusick 	i++;
938*8193Smckusick 	while(s[i])s[i++] = '0';
939*8193Smckusick 	return;
940*8193Smckusick 	}
941*8193Smckusick /* gather 24-hour stats and  mail to STATADDR */
942*8193Smckusick /* should also gather stats on # error msgs */
943*8193Smckusick dumpit(currt)
944*8193Smckusick   long currt; {
945*8193Smckusick 	register struct dumpstruc *p = &dump;
946*8193Smckusick 	register int ntot;
947*8193Smckusick 	long elapt;
948*8193Smckusick 	double cputime,utime,stime,bs,rawbs;
949*8193Smckusick 	char *sstartt;
950*8193Smckusick 	FILE *fdm;
951*8193Smckusick 	char froma[30];
952*8193Smckusick 	struct tms tbf;
953*8193Smckusick 
954*8193Smckusick 	/* if STATADDR is a file, the mail program this call will
955*8193Smckusick 	   ultimately execute must be able to deal with it,
956*8193Smckusick 	   and the remote mail program must be able to write on the
957*8193Smckusick 	   file, i.e. mode 666 */
958*8193Smckusick 	sprintf(froma,"%s=>",longname(local));
959*8193Smckusick 	strcat(froma,longname(remote));
960*8193Smckusick 	fdm = mailopen(STATADDR,froma,1,0);
961*8193Smckusick 	if(fdm == NULL)return;
962*8193Smckusick 
963*8193Smckusick 	/* calculate times */
964*8193Smckusick 	elapt = currt - dump.longtime;
965*8193Smckusick 	ntot = p->nnetcp + p->nnetmail + p->nsmail + p->nnetlpr
966*8193Smckusick 		+ p->nresp + p->nnet;
967*8193Smckusick 	sstartt = ctime(&dump.longtime) + 4;
968*8193Smckusick 	sstartt[strlen(sstartt) - 9] = 0;
969*8193Smckusick 
970*8193Smckusick 	times(&tbf);
971*8193Smckusick # ifndef NOFP
972*8193Smckusick 	utime = tbf.tms_utime + tbf.tms_cutime;
973*8193Smckusick 	stime = tbf.tms_stime + tbf.tms_cstime;
974*8193Smckusick 	cputime = utime + stime;
975*8193Smckusick 	if(elapt > 0)cputime = (cputime/elapt) * 100.0;
976*8193Smckusick 	else cputime = 0.0;
977*8193Smckusick 	utime = utime/60.0;
978*8193Smckusick 	stime = stime/60.0;
979*8193Smckusick 	cputime = cputime/60.0;
980*8193Smckusick 	bs = p->bytetot;
981*8193Smckusick 	if(p->elaptot > 0)bs = bs /p->elaptot;
982*8193Smckusick 	else bs = 0.0;
983*8193Smckusick # endif NOFP
984*8193Smckusick 
985*8193Smckusick 	/* print out the statistics */
986*8193Smckusick 	fprintf(fdm,"Subject: %s, %s, time %s\n",
987*8193Smckusick 		froma,sstartt, comptime(elapt));
988*8193Smckusick 	fprintf(fdm,"Command summary:\n");
989*8193Smckusick 	fprintf(fdm,"\t# sent %d\t# pass_thru %d\t# rcv %d:\t# netcp %d\n",
990*8193Smckusick 		p->nsend,p->npass,ntot,p->nnetcp);
991*8193Smckusick 	fprintf(fdm,"\t# netlpr %d\t# netmail %d\t# sendbmail %d\t# resp %d\n",
992*8193Smckusick 		p->nnetlpr,p->nnetmail,p->nsmail,p->nresp);
993*8193Smckusick 	fprintf(fdm,"Protocol summary:\n");
994*8193Smckusick 	fprintf(fdm,"\t# pk_sent %d\t# pk_rcv %d\t# b_sent %ld\t# b_rcv %ld\n",
995*8193Smckusick 		p->npacksent,p->npackrcv,p->nbytesent, p->nbytercv);
996*8193Smckusick 	fprintf(fdm,
997*8193Smckusick 		"\t# send_fails %d\t# retrans %d\t# abn %d\t\t# cksum_errs %d\n",
998*8193Smckusick 		p->nsendfail,p->nretrans, p->nabnormal,p->ncksum);
999*8193Smckusick # ifndef NOFP
1000*8193Smckusick 	fprintf(fdm,"Load:\tuser %4.1f\tsys %4.1f\tpct %5.2f\trate %6.1f\n",
1001*8193Smckusick 		utime,stime,cputime,bs);
1002*8193Smckusick 	rawbs = p->brawtot*100L;
1003*8193Smckusick 	rawbs = rawbs / linechars();
1004*8193Smckusick 	fprintf(fdm,"\trawbytes %ld\tuse %4.1f\n", p->brawtot,rawbs);
1005*8193Smckusick # endif NOFP
1006*8193Smckusick 	mailclose(fdm);
1007*8193Smckusick 
1008*8193Smckusick 	/* reset counters */
1009*8193Smckusick 	p->nbytesent = p->nbytercv = p->elaptot = p->bytetot = 0L;
1010*8193Smckusick 	p->nretrans = p->nloop = p->nabnormal = p->ncksum = 0;
1011*8193Smckusick 	p->npacksent = p->npackrcv = p->nnetcp = p->nnetmail = 0;
1012*8193Smckusick 	p->nsmail = p->nnetlpr = p->nnet = p->npass = 0;
1013*8193Smckusick 	p->nsend = p->nsendfail = 0;
1014*8193Smckusick 	dump.longtime = currt;
1015*8193Smckusick 	}
1016*8193Smckusick /* returns 1 if n is ok, 0 if not */
1017*8193Smckusick goodacctname(n)
1018*8193Smckusick   char *n; {
1019*8193Smckusick 	int i;
1020*8193Smckusick 	i = -1;
1021*8193Smckusick 	while(btable[++i].bname)
1022*8193Smckusick 		if(strcmp(btable[i].bname,n) == 0 &&
1023*8193Smckusick 			local == btable[i].bmach)return(0);
1024*8193Smckusick 	return(1);
1025*8193Smckusick 	}
1026*8193Smckusick demask(s)
1027*8193Smckusick   register char *s; {
1028*8193Smckusick /*
1029*8193Smckusick 	static char buf[20];
1030*8193Smckusick 	char skey[30];
1031*8193Smckusick 	makeuukey(skey,status.login,local);
1032*8193Smckusick 	strcpy(s,nbsdecrypt(s,skey,buf));
1033*8193Smckusick */
1034*8193Smckusick 	while(*s){
1035*8193Smckusick 		*s &= 0177;		/* strip quote bites */
1036*8193Smckusick 		*s++ ^= 040;		/* invert upper-lower */
1037*8193Smckusick 		}
1038*8193Smckusick 	}
1039*8193Smckusick /*VARARGS0*/
1040*8193Smckusick mreopen(fsendtofmach,phd,sfn,a,b,c){
1041*8193Smckusick /* simply handles errors by giving error msg */
1042*8193Smckusick 	if(freopen(a,b,c) == NULL)
1043*8193Smckusick 		errormsg(fsendtofmach,phd,sfn,"%s: %s",a,sys_errlist[errno]);
1044*8193Smckusick }
1045*8193Smckusick /*
1046*8193Smckusick 	addtopub(string, args)
1047*8193Smckusick 
1048*8193Smckusick 	add a message to the public logfile /usr/net/logfile.
1049*8193Smckusick 	note that the file must be writeable by everyone
1050*8193Smckusick 	if error messages from the netrcv subroutine
1051*8193Smckusick 	such as chdir errors are to be noticed.
1052*8193Smckusick */
1053*8193Smckusick /*VARARGS0*/
1054*8193Smckusick addtopublic(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n)
1055*8193Smckusick char *s;
1056*8193Smckusick {
1057*8193Smckusick 	static FILE *log = NULL;
1058*8193Smckusick 	if(log == NULL){
1059*8193Smckusick 		if(stat(publogfile,&statbuf) < 0)return;
1060*8193Smckusick 		log = fopen(publogfile,"a");
1061*8193Smckusick 		if(log == NULL)return;
1062*8193Smckusick 		}
1063*8193Smckusick 	fseek(log,0L,2);
1064*8193Smckusick 	fprintf(log,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n);
1065*8193Smckusick 	fflush(log);
1066*8193Smckusick 	}
1067*8193Smckusick /* set up a dummy environment for v7 /bin/sh */
1068*8193Smckusick setenv(home)
1069*8193Smckusick   char *home; {
1070*8193Smckusick 	static char *env[3],benv[2][50];
1071*8193Smckusick 	env[0] = benv[0];
1072*8193Smckusick 	env[1] = benv[1];
1073*8193Smckusick #ifdef CCV7
1074*8193Smckusick 	strcpy( env[0], "PATH=:.:/usr/cc/bin:/usr/ucb/bin" );
1075*8193Smckusick #else CCV7
1076*8193Smckusick 	strcpy(env[0],"PATH=:/bin:/usr/bin");
1077*8193Smckusick #endif CCV7
1078*8193Smckusick 	sprintf(env[1],"HOME=%s",home);
1079*8193Smckusick 	env[2] = 0;
1080*8193Smckusick 	environ = env;
1081*8193Smckusick 	}
1082*8193Smckusick /*
1083*8193Smckusick 	errormsg(fsendtofmach,phd,sfn,"string",arg(s))
1084*8193Smckusick 
1085*8193Smckusick 	Sends error message to user.
1086*8193Smckusick 	If fsendtofmach=TRUE, send to phd->hd_mchfrom, otherwise
1087*8193Smckusick 	send to phd->hd_mchto.
1088*8193Smckusick 	Also, if error occured during return of a "response",
1089*8193Smckusick 	send to local machine.
1090*8193Smckusick 
1091*8193Smckusick 	Note that errormsg can be called by the netrcv subroutine
1092*8193Smckusick 	after the setuid() call to the specific user, so the
1093*8193Smckusick 	user must be able to get off an error msg back to him,
1094*8193Smckusick 	and to write in the two log files.
1095*8193Smckusick 	Can't use -w,-x,-y,-z for the net cmd because must be root for those.
1096*8193Smckusick 
1097*8193Smckusick 	If sfn != NULL, then unlink sfn before exiting.
1098*8193Smckusick */
1099*8193Smckusick /*VARARGS0*/
1100*8193Smckusick errormsg(fsendtofmach,phd,sfn,s,a,b,c,d,e,f,g,h)
1101*8193Smckusick char fsendtofmach;
1102*8193Smckusick struct header *phd;
1103*8193Smckusick char *sfn,*s;
1104*8193Smckusick {
1105*8193Smckusick 	int rcode;
1106*8193Smckusick 	char errstr[BUFSIZ], cmdstr[BUFSIZ], rcmd[BUFSIZ];
1107*8193Smckusick 	char toadd[FNS], fromadd[FNS], mchto, mchfrom;
1108*8193Smckusick 	char snto[FNS], snfrom[FNS];
1109*8193Smckusick 
1110*8193Smckusick 	if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx");
1111*8193Smckusick 	/* will send to toadd, from fromadd */
1112*8193Smckusick 	if(!fsendtofmach || strcmp(phd->hd_scmdvirt,"response") == 0){
1113*8193Smckusick 		/* send to tomach mach, thus send to toaddr. */
1114*8193Smckusick 		/* if this is an error during a response, send to local mach. */
1115*8193Smckusick 		strcpy(toadd,  phd->hd_addrto);
1116*8193Smckusick 		strcpy(fromadd,phd->hd_addrfrom);
1117*8193Smckusick 	}
1118*8193Smckusick 	else {		/* send to remote mach, thus send back to addrfrom*/
1119*8193Smckusick 		strcpy(toadd,  phd->hd_addrfrom);
1120*8193Smckusick 		strcpy(fromadd,phd->hd_addrto);
1121*8193Smckusick 	}
1122*8193Smckusick 	sprintf(errstr,"Error: ");
1123*8193Smckusick 	sprintf(cmdstr,s,a,b,c,d,e,f,g,h);
1124*8193Smckusick 	strcat(errstr,cmdstr);
1125*8193Smckusick 	strcat(errstr,"\n");
1126*8193Smckusick 	addtolog(remote,errstr);
1127*8193Smckusick 	addtopublic(errstr);
1128*8193Smckusick 
1129*8193Smckusick 	mchto =   MchSFromAddr(snto,toadd);
1130*8193Smckusick 	mchfrom = MchSFromAddr(snfrom,fromadd);
1131*8193Smckusick 
1132*8193Smckusick 	sprintf(rcmd,
1133*8193Smckusick "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -y %s -c \"'%s'\" -e %ld",
1134*8193Smckusick 	MWRITECMD, snto, phd->hd_sttyname, phd->hd_lttytime,
1135*8193Smckusick 	local, snfrom,phd->hd_scmdvirt, phd->hd_ltimesent-TIMEBASE,
1136*8193Smckusick 	toadd, fromadd, phd->hd_lttytime, phd->hd_sttyname, phd->hd_scmdvirt,
1137*8193Smckusick 	phd->hd_ltimesent-TIMEBASE);
1138*8193Smckusick 
1139*8193Smckusick 	if(mchto == local)
1140*8193Smckusick 		sprintf(cmdstr, "echo \"%s\" | %s", errstr,rcmd);
1141*8193Smckusick 	else
1142*8193Smckusick 		sprintf(cmdstr,
1143*8193Smckusick 		"echo \"%s\" | %s -m%c -b -c errormessage -l network - %s",
1144*8193Smckusick 			errstr,netcmd,mchto,rcmd);
1145*8193Smckusick 	rcode = system(cmdstr);
1146*8193Smckusick 	debug( "errormsg: cmdstr = %s\n", cmdstr );
1147*8193Smckusick 	debug( "errormsg: rcode = %d\n", rcode );
1148*8193Smckusick 	if(sfn != NULL)unlink(sfn);
1149*8193Smckusick 	exit(EX_USAGE);
1150*8193Smckusick 	}
1151*8193Smckusick handlekill(){	/* SIGTERM signal */
1152*8193Smckusick 	long t;
1153*8193Smckusick 	/*
1154*8193Smckusick 	t = gettime();
1155*8193Smckusick 	dumpit(t);
1156*8193Smckusick 	*/
1157*8193Smckusick # ifdef NETLDISC
1158*8193Smckusick 	/* turn off net line discipline if possible */
1159*8193Smckusick 	netd.dp_linedis = 0;
1160*8193Smckusick 	ioctl(netd.dp_linefd,TIOCSETD,&netd.dp_linedis);
1161*8193Smckusick 	close(netd.dp_linefd);
1162*8193Smckusick 	printf("Network line discipline turned off.\n");
1163*8193Smckusick # endif NETLDISC
1164*8193Smckusick 	exit(EX_OK);	/* kill myself */
1165*8193Smckusick 	}
1166*8193Smckusick 
1167*8193Smckusick /* check a request to see if it is an acct pair */
1168*8193Smckusick /* returns 1 if it is, 0 if not */
1169*8193Smckusick static facctpaircheck(phd)
1170*8193Smckusick register struct header *phd;
1171*8193Smckusick {
1172*8193Smckusick 	return(0);
1173*8193Smckusick }
1174*8193Smckusick 
1175