1 static char sccsid[] = "@(#)netdaemon.c 4.2 (Berkeley) 09/12/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 unsigned 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 send(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); 298 bwrite: 299 dump.nsendfail++; 300 fclose(jfile); 301 addtolog(remote,"^F%c\n",remote); 302 return(0); 303 sfail: 304 error("%s: %s",jname,sys_errlist[errno]); 305 dump.nsendfail++; 306 return(0); 307 } 308 netrcv(){ 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 */ 393 forw: 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){ 438 # ifndef V6 439 RENICE0(); 440 # endif V6 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"); 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 wait(&dummy); 469 return(1); /* normal return */ 470 } 471 /* this is a child, who will go ahead and execute the command */ 472 /* running uid=0 at this point */ 473 # ifndef V6 474 RENICE0(); 475 # endif V6 476 /* nice(0 set back to 0 */ 477 #ifdef CCV7 478 /* separate group process */ 479 setpgrp(); 480 #endif CCV7 481 482 while((pid = fork()) == -1)sleep(2); 483 if(pid != 0)exit(EX_OK); 484 485 /* child process which forks and waits */ 486 mktemp(resfile); 487 while((pid = fork()) == -1)sleep(2); 488 if(pid == 0){ 489 /* child */ 490 strcpy(status.loginshell,Bsh); 491 frommach = hd.hd_mchfrom; 492 n = check(&hd,(hd.hd_code == 'q')); 493 if(!n)errormsg(TRUE,&hd,NULL, 494 "Bad remote login/password '%s'",hd.hd_snto); 495 temp = fopen(resfile,"w"); 496 if(temp == NULL) 497 errormsg(TRUE,&hd,NULL, 498 "Create file %s: %s",resfile,sys_errlist[errno]); 499 fclose(temp); 500 chmod(resfile,0600); 501 mchown(resfile,status.muid,status.mgid); 502 if(sin) 503 mchown(tempfile,status.muid,status.mgid); 504 else tempfile[0] = 0; 505 setgid(status.mgid); 506 setuid(status.muid); 507 /* after this point our gid, uid is the target user's */ 508 excmd(&hd,resfile,tempfile); 509 } 510 /* parent */ 511 wait(&rcode); 512 rcode = (((rcode&077400) >>8) &0177); 513 /* 514 fclose(stdin); 515 fclose(stdout); 516 fclose(stderr); 517 */ 518 if(sin)unlink(tempfile); 519 /* 520 now send something back to the sender 521 unless this was a response (file or message) 522 */ 523 if((hd.hd_code == 'q' || hd.hd_code == 'y') 524 && (hd.hd_srespfile[0] || !hd.hd_fnonotify)) 525 sndresponse(&hd,rcode); 526 unlink(resfile); 527 s = ctime(&rcvfinish); 528 s += 4; 529 s[strlen(s) -8] = 0; 530 diff = rcvfinish - otime; 531 if(diff < 1)diff = 1; /* avoid dividing by zero */ 532 dump.bytetot += olength; 533 dump.elaptot += diff; 534 sprintf(buf,"%s rcv %c:%-8s (%s)", 535 s,hd.hd_mchfrom,hd.hd_snfrom,hd.hd_snto); 536 addtolog(remote,"%s C: %s\n",buf,hd.hd_scmdvirt); 537 addtopublic("%s R: %d C: %s\n",buf,rcode,hd.hd_scmdvirt); 538 nt = rcvfinish - hd.hd_ltimesent; 539 buf[0] = 0; 540 if(nt > 0L)sprintf(buf," took (%s)",comptime(nt)); 541 # ifndef NOFP 542 r = olength; 543 r = r/diff; 544 addtolog(remote,"\t\tR: %d%s %ldb %ldsec %4.1fb/sec\n", 545 rcode,buf,olength,diff,r); 546 r = dump.braw; 547 r = r/diff; 548 addtolog(remote,"\t\t%4.1frb/sec %4.1f%% use\n",r,(r/linechars())*100L); 549 # else NOFP 550 addtolog(remote,"\t\tR: %d%s %ldb %ldsec\n", 551 rcode,buf,olength,diff); 552 # endif NOFP 553 exit(EX_OK); 554 /*UNREACHED*/ 555 } 556 long linechars(){ 557 if(netd.dp_inspeed == 13)return(960L); 558 else return(120L); 559 } 560 /* 561 execute the user's command 562 this procedure is executed with uid, gid of the user 563 */ 564 excmd(phd,tempresfile,tempinfile) 565 register struct header *phd; 566 char *tempresfile, *tempinfile; 567 { 568 FILE *fd; 569 int i, uid; 570 register char *s, c; 571 572 uid = getuid(); 573 uid = uidmask(uid); 574 status.muid = uidmask(status.muid); 575 if(uid != status.muid)error("setuid fails"); 576 debug("uid: %u, gid: %u\n",uid,status.mgid); 577 /* check for allowed root commands, for security reasons */ 578 if(uid == SUPERUSER){ 579 s = phd->hd_scmdact; 580 while(*s && *s != ' ')s++; 581 c = *s; 582 *s = 0; 583 /* these are the only commands root may execute */ 584 if(strcmp(phd->hd_scmdact,"cat") != 0 585 && strcmp(phd->hd_scmdact,MWRITECMD) != 0 586 && strcmp(phd->hd_scmdact,"/bin/cat") != 0 587 && strcmp(phd->hd_scmdact,"netrm") != 0 588 && strcmp(phd->hd_scmdact,"/usr/lib/tq") != 0 589 && strcmp(phd->hd_scmdact,"/usr/cc/lib/tq") != 0 590 && strcmp(phd->hd_scmdact,"/usr/lib/rtrrm") != 0 591 && strcmp(phd->hd_scmdact,"/usr/cc/lib/rtrrm") != 0 592 && strcmp(phd->hd_scmdact,"lpr") != 0) 593 errormsg(TRUE,phd,tempresfile, 594 "Not allowed to execute '%s' as root", 595 phd->hd_scmdact); 596 *s = c; 597 } 598 if(chdir(status.dir) < 0) 599 errormsg(TRUE,phd,tempresfile, 600 "chdir %s: %s",status.dir,sys_errlist[errno]); 601 setenv(status.dir); /* set up v7 environment */ 602 if(tempinfile[0])mreopen(TRUE,phd,tempresfile,tempinfile,"r",stdin); 603 else if(phd->hd_sinfile[0])mreopen(TRUE,phd,tempresfile,phd->hd_sinfile,"r",stdin); 604 else mreopen(TRUE,phd,tempresfile,"/dev/null","r",stdin); 605 if(phd->hd_code == 's' && phd->hd_soutfile[0]){ 606 if(stat(phd->hd_soutfile,&statbuf) < 0 607 || getsize(&statbuf) != 0) 608 errormsg(FALSE,phd,tempresfile,"Bad result file '%s'",phd->hd_soutfile); 609 mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout); 610 } 611 else if(phd->hd_soutfile[0]){ 612 fd = fopen(phd->hd_soutfile,"w"); 613 if(fd == NULL) 614 errormsg(TRUE,phd,tempresfile,"Open file %s: %s", 615 phd->hd_soutfile,sys_errlist[errno]); 616 fclose(fd); 617 mreopen(TRUE,phd,tempresfile,phd->hd_soutfile,"w",stdout); 618 } 619 else mreopen(TRUE,phd,tempresfile,tempresfile,"a",stdout); 620 debug("exec '%s'\n",phd->hd_scmdact); 621 if(debugflg == 0){ 622 /* cheat */ 623 close(2); 624 dup(1); 625 /* 626 mreopen(TRUE,phd,tempresfile,tempresfile,"a",stderr); 627 */ 628 } 629 for(i=3;i<15;i++)close(i); 630 if(strcmp(phd->hd_scmdact,"cat") == 0 631 || strcmp(phd->hd_scmdact,"/bin/cat") == 0)excat(); 632 do { 633 mexecl(status.loginshell,"sh","-c",phd->hd_scmdact,0); 634 sleep(2); 635 } while(errno == ETXTBSY); 636 perror(status.loginshell); 637 exit(EX_UNAVAILABLE); 638 } 639 /* 640 send back a response 641 642 if errormsg was called the resfile should be unlinked, 643 to avoid two messages being sent there 644 */ 645 sndresponse(phd,rcode) 646 unsigned rcode; 647 struct header *phd; 648 { 649 char cmdstr[BUFSIZ], buf[BUFSIZ]; 650 int dummy; 651 long maxfile = MAXFILELARGE; 652 /* send response back if a response file 653 was given or if mail/write is allowed */ 654 if(stat(resfile,&statbuf) < 0){ 655 error("%s %s",resfile,sys_errlist[errno]); 656 return; 657 } 658 if(getsize(&statbuf) >= maxfile){ 659 errormsg(TRUE,phd,"Result file too large - not sent"); 660 return; 661 } 662 if(getsize(&statbuf) == 0){ 663 /* response file specified, no output generated */ 664 if(phd->hd_srespfile[0] != 0)return; 665 /* quiet option - no output and a rcode of 0 */ 666 if(rcode == 0 && phd->hd_fquiet)return; 667 } 668 /* use both old and new mwrite parm lists */ 669 670 if(phd->hd_srespfile[0]) 671 sprintf(cmdstr,"-o %s cat",phd->hd_srespfile); 672 else sprintf(cmdstr, 673 "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -c \"'%s'\" -y %s -e %ld -r %d", 674 MWRITECMD, phd->hd_snfrom,phd->hd_sttyname,phd->hd_lttytime, 675 phd->hd_mchto,phd->hd_snto, phd->hd_scmdvirt,phd->hd_ltimesent-TIMEBASE, 676 phd->hd_addrfrom, phd->hd_addrto, phd->hd_lttytime, 677 phd->hd_scmdvirt, phd->hd_sttyname, phd->hd_ltimesent-TIMEBASE, rcode); 678 679 sprintf(buf,"%s -m%c -z -b -l %s -s %s -c response %s", 680 netcmd,phd->hd_mchfrom,phd->hd_snfrom,resfile,cmdstr); 681 dummy = system(buf); /* execute command buf */ 682 } 683 684 /* 685 686 excat 687 does nothing more than copy standard input to standard 688 output, like the cat command, but reports write errors. 689 Uses getc and putc rather than fwrite and fread because 690 the latter call getc and putc. 691 */ 692 excat(){ 693 register int n; 694 char buf[BUFSIZ]; 695 696 errno = 0; 697 while((n = read(0,buf,BUFSIZ)) > 0){ 698 if(write(1,buf,n) != n){ 699 perror("filecat: stdout"); 700 exit(EX_OSFILE); 701 } 702 } 703 if(errno){ 704 perror("filecat: stdin"); 705 exit(EX_OSFILE); 706 } 707 exit(EX_OK); 708 } 709 /* returns errors for netrcv() */ 710 static readhd(phd) 711 register struct header *phd; 712 { 713 char cflag, sbuf[BUFSIZ], parmlist[PARMLIST], *cptr; 714 int i, code; 715 code = mgetc(); 716 phd->hd_mchto = mgetc(); 717 if(code != 'q' && code != 'y' && code != 'w' && code != 's'){ 718 error("bad code"); 719 return(-1); 720 } 721 phd->hd_code = code; 722 for(i = 0; i < MAXINX; i++) 723 if(phd->hd_mchto == inxtoch(i)) break; 724 if(i >= MAXINX){ 725 error("bad phd->hd_mchto"); 726 return(-1); 727 } 728 if(phd->hd_mchto != local)return(-3); /* being forwarded through us */ 729 phd->hd_mchfrom = mgetc(); 730 phd->hd_vmajor = mgetc(); 731 phd->hd_vminor = mgetc(); 732 i = 0; 733 i += mgets(phd->hd_snto,NS); 734 i += mgets(phd->hd_spasswd,20); 735 i += mgets(phd->hd_sinfile,FNS); 736 i += mgets(phd->hd_soutfile,FNS); 737 i += mgets(phd->hd_srespfile,FNS); 738 i += mgets(phd->hd_snfrom,NS); 739 740 /* addrfrom is the person who sent this to us, 741 addrto is the person who received the command, i.e. 742 addrto is on this machine */ 743 if(phd->hd_snfrom[0] == 0)strcpy(phd->hd_snfrom,"root"); 744 sprintf(phd->hd_addrfrom, "%s:%s",longname(phd->hd_mchfrom),phd->hd_snfrom); 745 sprintf(phd->hd_addrto, "%s:%s",longname(phd->hd_mchto),phd->hd_snto); 746 747 i += mgets(phd->hd_sttyname,20); 748 if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx"); 749 cflag = mgetc(); 750 if(!phd->hd_mchfrom || !phd->hd_code || !cflag || !phd->hd_vmajor || !phd->hd_vminor){ 751 error("mgetc fails"); 752 return(-1); 753 } 754 755 cflag -= 'a'; 756 phd->hd_fnonotify = (cflag & F_NONOTIFY); 757 phd->hd_fquiet = (cflag & F_QUIET); 758 759 phd->hd_vmajor -= 'a'; 760 phd->hd_vminor -= 'a'; 761 762 i += mgets(sbuf,BUFSIZ); 763 phd->hd_lttytime = 0; 764 sscanf(sbuf,"%lo",&phd->hd_lttytime); 765 766 i += mgets(parmlist,PARMLIST); 767 #ifdef CRN 768 cptr = parmlist; 769 while( *cptr != '(' ) 770 cptr++; 771 *cptr = '\0'; 772 strcpy( phd->hd_ijobno, parmlist ); 773 *cptr = '('; 774 #else CRN 775 strcpy( phd->hd_ijobno, "XYZZ" ); 776 #endif CRN 777 /* keep variable parameter list in crn slot */ 778 parseparmlist(parmlist); 779 780 i += mgets(sbuf,BUFSIZ); /* time sent */ 781 sscanf(sbuf,"%ld",&phd->hd_ltimesent); 782 phd->hd_ltimesent += TIMEBASE; 783 i += mgetcmd(phd->hd_scmdact); 784 i += mgetcmd(phd->hd_scmdvirt); 785 if(i != 0){error("mgets fails"); return(-1);} 786 if(phd->hd_scmdvirt[0] == 0)strcpy(phd->hd_scmdvirt,phd->hd_scmdact); 787 return(0); 788 } 789 /* 790 check() -- verify login name and password 791 phd = login,passwd 792 fverify = 1 if password must check 793 Returns 1 if password is ok, 0 if not. 794 */ 795 check(phd,fverify) /* 1 if OK, 0 if not */ 796 register struct header *phd; 797 int fverify; 798 { 799 char *sencpasswd, *u, *nullstr = ""; 800 struct passwd *pwd; 801 #ifdef CRN 802 struct gecos *gcos; 803 #endif CRN 804 if(phd->hd_snto[0] == 0)return(!fverify); 805 debug("check: phd->hd_snto = %s\n", phd->hd_snto ); 806 if(!goodacctname(phd->hd_snto))return(!fverify); 807 pwd = getpwnam(phd->hd_snto); 808 debug("got pwd=%d, pwd->pw_passwd = %s\n",pwd, pwd->pw_passwd); 809 if(pwd == NULL)return(!fverify); 810 if(*phd->hd_spasswd)sencpasswd = crypt(phd->hd_spasswd,pwd->pw_passwd); 811 else sencpasswd = nullstr; 812 debug("check: passwd(rcvd)=%s, passwd(file) = %s, passwd(encrypt)=%s\n", phd->hd_spasswd, pwd->pw_passwd, sencpasswd ); 813 814 status.muid = guid(pwd->pw_uid,pwd->pw_gid); 815 status.mgid = pwd->pw_gid; 816 #ifdef CRN 817 if( (gcos=pwgecos( pwd->pw_gecos )) == NULL ) 818 strcpy( status.jobno, MAGICCRN ); 819 else 820 strcpy( status.jobno, gcos->gc_crn ); 821 #else CRN 822 strcpy( status.jobno, "XYZZ"); 823 #endif CRN 824 strcpy(status.dir,pwd->pw_dir); 825 strcpy(status.loginshell,pwd->pw_shell); 826 u = status.loginshell; 827 if(u[0] == 0 || strcmp("/bin/sbash",u) == 0)strcpy(u,Bsh); 828 829 getpwdf(pwd); 830 /* ignore network passwd */ 831 /* acct is not a pair, acct is not "network", passwd is incorrect, 832 and verification is requested => passwd not ok */ 833 if(!facctpaircheck(phd) && strcmp(phd->hd_snto,"network") != 0 834 && strcmp(pwd->pw_passwd,sencpasswd) != 0 && fverify) 835 return(0); 836 return(1); /* otherwise passwd ok */ 837 } 838 mread(b,n) 839 register int n; { 840 if(length <= 0)return(0); 841 if(length < n)n = length; 842 n = nread(b,n); 843 if(n != BROKENREAD)length -= n; 844 return(n); 845 } 846 char mgetc(){ /* returns 0 if fail */ 847 register char c; 848 register int n; 849 char buf[3]; 850 if((n=nread(buf,3)) == BROKENREAD)return(0); 851 if(n != 3){error("bad read %d",n); return(0); } 852 c = buf[0]; 853 if(buf[1] != ' ' && buf[1] != ':'){error("Bad char %c",buf[1]); return(0); } 854 length -= 3; 855 if(length < 0){error("length wrong2 %ld",length); return(0); } 856 return(c); 857 } 858 /* read in string over the network wire */ 859 /* put string in s, max length is maxlen */ 860 mgets(s,maxlen) /* returns 0 if ok, 1 if not */ 861 int maxlen; 862 register char *s; { 863 register char *q; 864 register int n; 865 char c; 866 q = s; 867 for(;;) { 868 if((n=nread(&c,1)) == BROKENREAD){ 869 *s = 0; 870 error("mgets %s",s); 871 return(1); 872 } 873 if(n == 0)break; 874 if(c == '\\'){ 875 if((n=nread(&c,1)) == BROKENREAD){ 876 *s = 0; 877 error("mgets %s",s); 878 return(1); 879 } 880 if(n == 0)break; 881 } 882 if(c == ' ')break; 883 if(maxlen-- > 0) *s++ = c; 884 } 885 *s = 0; 886 if(nread(&c,1) == BROKENREAD){ 887 error("mgets %s",s); 888 return(1); 889 } 890 length -= (s - q + 2); 891 if(length < 0){error("length wrong1 %ld %s",length,q); return(-1); } 892 if(maxlen < 0) 893 error("mgets - string too long"); 894 return(0); 895 } 896 mgetcmd(s) /* returns 0 if succeed, 1 otherwise */ 897 char *s; { 898 int i,n; 899 char c; 900 i = 0; 901 for(;;){ 902 if((n=nread(&c,1)) == BROKENREAD){ 903 s[i] = 0; 904 error("mgetcmd %s",s); 905 return(1); 906 } 907 if(n <= 0 || c == '\n')break; 908 if(c == '\\'){ 909 if(nread(&c,1) == BROKENREAD){ 910 s[i] = 0; 911 error("mgetcmd %s",s); 912 return(1); 913 } 914 length--; 915 } 916 s[i++] = c; 917 length--; 918 } 919 s[i] = 0; 920 length--; 921 return(0); 922 } 923 increment(s) 924 char *s; { 925 int i; 926 char *p; 927 i = strlen(s) - 1; 928 while(s[i] == '9')i--; 929 if(s[i] < '0' || s[i] > '9'){ 930 p = s+i+1; 931 while(*p)*p++ = '0'; 932 return; 933 } 934 (s[i])++; 935 i++; 936 while(s[i])s[i++] = '0'; 937 return; 938 } 939 /* gather 24-hour stats and mail to STATADDR */ 940 /* should also gather stats on # error msgs */ 941 dumpit(currt) 942 long currt; { 943 register struct dumpstruc *p = &dump; 944 register int ntot; 945 long elapt; 946 double cputime,utime,stime,bs,rawbs; 947 char *sstartt; 948 FILE *fdm; 949 char froma[30]; 950 struct tms tbf; 951 952 /* if STATADDR is a file, the mail program this call will 953 ultimately execute must be able to deal with it, 954 and the remote mail program must be able to write on the 955 file, i.e. mode 666 */ 956 sprintf(froma,"%s=>",longname(local)); 957 strcat(froma,longname(remote)); 958 fdm = mailopen(STATADDR,froma,1,0); 959 if(fdm == NULL)return; 960 961 /* calculate times */ 962 elapt = currt - dump.longtime; 963 ntot = p->nnetcp + p->nnetmail + p->nsmail + p->nnetlpr 964 + p->nresp + p->nnet; 965 sstartt = ctime(&dump.longtime) + 4; 966 sstartt[strlen(sstartt) - 9] = 0; 967 968 times(&tbf); 969 # ifndef NOFP 970 utime = tbf.tms_utime + tbf.tms_cutime; 971 stime = tbf.tms_stime + tbf.tms_cstime; 972 cputime = utime + stime; 973 if(elapt > 0)cputime = (cputime/elapt) * 100.0; 974 else cputime = 0.0; 975 utime = utime/60.0; 976 stime = stime/60.0; 977 cputime = cputime/60.0; 978 bs = p->bytetot; 979 if(p->elaptot > 0)bs = bs /p->elaptot; 980 else bs = 0.0; 981 # endif NOFP 982 983 /* print out the statistics */ 984 fprintf(fdm,"Subject: %s, %s, time %s\n", 985 froma,sstartt, comptime(elapt)); 986 fprintf(fdm,"Command summary:\n"); 987 fprintf(fdm,"\t# sent %d\t# pass_thru %d\t# rcv %d:\t# netcp %d\n", 988 p->nsend,p->npass,ntot,p->nnetcp); 989 fprintf(fdm,"\t# netlpr %d\t# netmail %d\t# sendbmail %d\t# resp %d\n", 990 p->nnetlpr,p->nnetmail,p->nsmail,p->nresp); 991 fprintf(fdm,"Protocol summary:\n"); 992 fprintf(fdm,"\t# pk_sent %d\t# pk_rcv %d\t# b_sent %ld\t# b_rcv %ld\n", 993 p->npacksent,p->npackrcv,p->nbytesent, p->nbytercv); 994 fprintf(fdm, 995 "\t# send_fails %d\t# retrans %d\t# abn %d\t\t# cksum_errs %d\n", 996 p->nsendfail,p->nretrans, p->nabnormal,p->ncksum); 997 # ifndef NOFP 998 fprintf(fdm,"Load:\tuser %4.1f\tsys %4.1f\tpct %5.2f\trate %6.1f\n", 999 utime,stime,cputime,bs); 1000 rawbs = p->brawtot*100L; 1001 rawbs = rawbs / linechars(); 1002 fprintf(fdm,"\trawbytes %ld\tuse %4.1f\n", p->brawtot,rawbs); 1003 # endif NOFP 1004 mailclose(fdm); 1005 1006 /* reset counters */ 1007 p->nbytesent = p->nbytercv = p->elaptot = p->bytetot = 0L; 1008 p->nretrans = p->nloop = p->nabnormal = p->ncksum = 0; 1009 p->npacksent = p->npackrcv = p->nnetcp = p->nnetmail = 0; 1010 p->nsmail = p->nnetlpr = p->nnet = p->npass = 0; 1011 p->nsend = p->nsendfail = 0; 1012 dump.longtime = currt; 1013 } 1014 /* returns 1 if n is ok, 0 if not */ 1015 goodacctname(n) 1016 char *n; { 1017 int i; 1018 i = -1; 1019 while(btable[++i].bname) 1020 if(strcmp(btable[i].bname,n) == 0 && 1021 local == btable[i].bmach)return(0); 1022 return(1); 1023 } 1024 demask(s) 1025 register char *s; { 1026 /* 1027 static char buf[20]; 1028 char skey[30]; 1029 makeuukey(skey,status.login,local); 1030 strcpy(s,nbsdecrypt(s,skey,buf)); 1031 */ 1032 while(*s){ 1033 *s &= 0177; /* strip quote bites */ 1034 *s++ ^= 040; /* invert upper-lower */ 1035 } 1036 } 1037 /*VARARGS0*/ 1038 mreopen(fsendtofmach,phd,sfn,a,b,c){ 1039 /* simply handles errors by giving error msg */ 1040 if(freopen(a,b,c) == NULL) 1041 errormsg(fsendtofmach,phd,sfn,"%s: %s",a,sys_errlist[errno]); 1042 } 1043 /* 1044 addtopub(string, args) 1045 1046 add a message to the public logfile /usr/net/logfile. 1047 note that the file must be writeable by everyone 1048 if error messages from the netrcv subroutine 1049 such as chdir errors are to be noticed. 1050 */ 1051 /*VARARGS0*/ 1052 addtopublic(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n) 1053 char *s; 1054 { 1055 static FILE *log = NULL; 1056 if(log == NULL){ 1057 if(stat(publogfile,&statbuf) < 0)return; 1058 log = fopen(publogfile,"a"); 1059 if(log == NULL)return; 1060 } 1061 fseek(log,0L,2); 1062 fprintf(log,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n); 1063 fflush(log); 1064 } 1065 /* set up a dummy environment for v7 /bin/sh */ 1066 setenv(home) 1067 char *home; { 1068 static char *env[3],benv[2][50]; 1069 env[0] = benv[0]; 1070 env[1] = benv[1]; 1071 #ifdef CCV7 1072 strcpy( env[0], "PATH=:.:/usr/cc/bin:/usr/ucb/bin" ); 1073 #else CCV7 1074 strcpy(env[0],"PATH=:/bin:/usr/bin"); 1075 #endif CCV7 1076 sprintf(env[1],"HOME=%s",home); 1077 env[2] = 0; 1078 environ = env; 1079 } 1080 /* 1081 errormsg(fsendtofmach,phd,sfn,"string",arg(s)) 1082 1083 Sends error message to user. 1084 If fsendtofmach=TRUE, send to phd->hd_mchfrom, otherwise 1085 send to phd->hd_mchto. 1086 Also, if error occured during return of a "response", 1087 send to local machine. 1088 1089 Note that errormsg can be called by the netrcv subroutine 1090 after the setuid() call to the specific user, so the 1091 user must be able to get off an error msg back to him, 1092 and to write in the two log files. 1093 Can't use -w,-x,-y,-z for the net cmd because must be root for those. 1094 1095 If sfn != NULL, then unlink sfn before exiting. 1096 */ 1097 /*VARARGS0*/ 1098 errormsg(fsendtofmach,phd,sfn,s,a,b,c,d,e,f,g,h) 1099 char fsendtofmach; 1100 struct header *phd; 1101 char *sfn,*s; 1102 { 1103 int rcode; 1104 char errstr[BUFSIZ], cmdstr[BUFSIZ], rcmd[BUFSIZ]; 1105 char toadd[FNS], fromadd[FNS], mchto, mchfrom; 1106 char snto[FNS], snfrom[FNS]; 1107 1108 if(phd->hd_sttyname[0] == 0)strcpy(phd->hd_sttyname,"/dev/ttyx"); 1109 /* will send to toadd, from fromadd */ 1110 if(!fsendtofmach || strcmp(phd->hd_scmdvirt,"response") == 0){ 1111 /* send to tomach mach, thus send to toaddr. */ 1112 /* if this is an error during a response, send to local mach. */ 1113 strcpy(toadd, phd->hd_addrto); 1114 strcpy(fromadd,phd->hd_addrfrom); 1115 } 1116 else { /* send to remote mach, thus send back to addrfrom*/ 1117 strcpy(toadd, phd->hd_addrfrom); 1118 strcpy(fromadd,phd->hd_addrto); 1119 } 1120 sprintf(errstr,"Error: "); 1121 sprintf(cmdstr,s,a,b,c,d,e,f,g,h); 1122 strcat(errstr,cmdstr); 1123 strcat(errstr,"\n"); 1124 addtolog(remote,errstr); 1125 addtopublic(errstr); 1126 1127 mchto = MchSFromAddr(snto,toadd); 1128 mchfrom = MchSFromAddr(snfrom,fromadd); 1129 1130 sprintf(rcmd, 1131 "%s %s %s %lo %c %s \"'%s'\" %ld -t %s -f %s -x %ld -y %s -c \"'%s'\" -e %ld", 1132 MWRITECMD, snto, phd->hd_sttyname, phd->hd_lttytime, 1133 local, snfrom,phd->hd_scmdvirt, phd->hd_ltimesent-TIMEBASE, 1134 toadd, fromadd, phd->hd_lttytime, phd->hd_sttyname, phd->hd_scmdvirt, 1135 phd->hd_ltimesent-TIMEBASE); 1136 1137 if(mchto == local) 1138 sprintf(cmdstr, "echo \"%s\" | %s", errstr,rcmd); 1139 else 1140 sprintf(cmdstr, 1141 "echo \"%s\" | %s -m%c -b -c errormessage -l network - %s", 1142 errstr,netcmd,mchto,rcmd); 1143 rcode = system(cmdstr); 1144 debug( "errormsg: cmdstr = %s\n", cmdstr ); 1145 debug( "errormsg: rcode = %d\n", rcode ); 1146 if(sfn != NULL)unlink(sfn); 1147 exit(EX_USAGE); 1148 } 1149 handlekill(){ /* SIGTERM signal */ 1150 long t; 1151 /* 1152 t = gettime(); 1153 dumpit(t); 1154 */ 1155 # ifdef NETLDISC 1156 /* turn off net line discipline if possible */ 1157 netd.dp_linedis = 0; 1158 ioctl(netd.dp_linefd,TIOCSETD,&netd.dp_linedis); 1159 close(netd.dp_linefd); 1160 printf("Network line discipline turned off.\n"); 1161 # endif NETLDISC 1162 exit(EX_OK); /* kill myself */ 1163 } 1164 1165 /* check a request to see if it is an acct pair */ 1166 /* returns 1 if it is, 0 if not */ 1167 static facctpaircheck(phd) 1168 register struct header *phd; 1169 { 1170 return(0); 1171 } 1172 1173