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