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