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