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