1 static char sccsid[] = "@(#)netdaemon.c 4.3 (Berkeley) 10/02/82"; 2 3 /* sccs id variable */ 4 static char *netdaemon_sid = "@(#)netdaemon.c 1.10"; 5 6 /* 7 8 The daemon program that runs the network. 9 10 Usage: 11 netdaemon -m mach [-r readfd] [-w writefd] [-d] [-h] 12 [-os] [-or] [-ou num] [-p len] [-8] [-l] 13 14 Must be started by root. 15 Options: 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 */ 40 extern char **environ; 41 struct dumpstruc dump; 42 struct bstruct btable[]; 43 struct daemonparms netd; 44 struct userinfo status; 45 46 /* local variables */ 47 static long length; 48 static DIR *dir; 49 /* static char sheader[] = "ABCDE"; */ 50 static char tempfile[]= TEMPFILE; 51 static char publogfile[]= PUBLOGFILE; 52 static struct stat statbuf; 53 int handlekill(); 54 static char frommach; 55 long linechars(); 56 57 main(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 } 88 dir = opendir(senddir); 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(<ime)); 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.*/ 111 mainloop(){ 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 */ 132 printstat(){ 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 */ 145 netsend(){ 146 static long lasttime = 0; 147 static char nleft = 1; 148 long lFileLen,diff; 149 double drate; 150 register int uid,uidBest; 151 char *sdate,*sn,*swait; 152 long ot,nt,filesize; 153 register int i; 154 char stemp[20]; 155 static char jname[FNS]; 156 register struct direct *dp; 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 rewinddir(dir); 166 lFileLen = 10000000L; 167 nleft = 0; 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 173 || statbuf.st_mode == 0) 174 continue; 175 dp->d_name[0] = 'd'; 176 if(stat(dp->d_name,&statbuf) < 0 || statbuf.st_mode == 0) 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 188 debug("sending large file %s\n", dp->d_name ); 189 } 190 #endif DONTHOLDBIG 191 if(lFileLen > filesize){ 192 lFileLen = filesize; 193 strcpy(jname,dp->d_name); 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 */ 241 day() 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 255 int subs; 256 257 send(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); 300 bwrite: 301 dump.nsendfail++; 302 fclose(jfile); 303 addtolog(remote,"^F%c\n",remote); 304 return(0); 305 sfail: 306 error("%s: %s",jname,sys_errlist[errno]); 307 dump.nsendfail++; 308 return(0); 309 } 310 netrcv(){ 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 */ 395 forw: 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 RENICE0(); 441 #ifdef CCV7 442 /* make sure the spawned child has it's own 443 group process to avoid the nasty 444 "try again" message 445 */ 446 setpgrp(); 447 #endif CCV7 448 execl(netcmd,"net","-x","-m",longname(hd.hd_mchto), 449 "-s",tempfile,0); 450 error("%s: %s",netcmd,sys_errlist[errno]); 451 exit(EX_UNAVAILABLE); 452 } 453 wait(&rcode); 454 unlink(tempfile); 455 rcode >>= 8; 456 if(rcode != 0) 457 error("pass-thru rcode %d", rcode); 458 debug("passthru to %c code %c rcode %d", 459 hd.hd_mchto,hd.hd_code,rcode); 460 return(1); 461 } 462 } 463 if(length > 0){error("file too short"); return(-1); } 464 rcvfinish = gettime(); 465 466 while((pid = fork()) == -1)sleep(2); 467 if(pid > 0){ 468 if (++subs > 10) 469 while( wait(&dummy) != -1) --subs; 470 return(1); /* normal return */ 471 } 472 /* this is a child, who will go ahead and execute the command */ 473 /* running uid=0 at this point */ 474 RENICE0(); 475 /* nice(0 set back to 0 */ 476 #ifdef CCV7 477 /* separate group process */ 478 setpgrp(); 479 #endif CCV7 480 481 482 /* 483 while((pid = fork()) == -1)sleep(2); 484 if(pid != 0)exit(EX_OK); 485 */ 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 } 558 long 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 */ 566 excmd(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 */ 647 sndresponse(phd,rcode) 648 unsigned rcode; 649 struct 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 */ 694 excat(){ 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() */ 712 static readhd(phd) 713 register 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 */ 797 check(phd,fverify) /* 1 if OK, 0 if not */ 798 register struct header *phd; 799 int 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 } 840 mread(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 } 848 char 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 */ 862 mgets(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 } 898 mgetcmd(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 } 925 increment(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 */ 943 dumpit(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 */ 1017 goodacctname(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 } 1026 demask(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*/ 1040 mreopen(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*/ 1054 addtopublic(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n) 1055 char *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 */ 1068 setenv(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*/ 1100 errormsg(fsendtofmach,phd,sfn,s,a,b,c,d,e,f,g,h) 1101 char fsendtofmach; 1102 struct header *phd; 1103 char *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 } 1151 handlekill(){ /* 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 */ 1169 static facctpaircheck(phd) 1170 register struct header *phd; 1171 { 1172 return(0); 1173 } 1174 1175