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