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(&ltime));
  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: }

Defined functions

addtopublic defined in line 972; used 4 times
check defined in line 723; used 1 times
demask defined in line 944; used 1 times
dumpit defined in line 860; used 1 times
errormsg defined in line 1014; used 8 times
excat defined in line 631; used 1 times
excmd defined in line 503; used 1 times
facctpaircheck defined in line 1074; used 1 times
goodacctname defined in line 935; used 1 times
handlekill defined in line 1063; used 2 times
increment defined in line 842; used 1 times
linechars defined in line 495; used 3 times
main defined in line 51; never used
mainloop defined in line 96; used 1 times
  • in line 92
mgetc defined in line 765; used 7 times
mgetcmd defined in line 815; used 2 times
mgets defined in line 779; used 10 times
mread defined in line 757; used 1 times
mreopen defined in line 958; used 6 times
netrcv defined in line 266; used 1 times
netsend defined in line 130; used 1 times
printstat defined in line 117; used 1 times
readhd defined in line 649; used 1 times
send defined in line 213; used 1 times
setenv defined in line 986; used 1 times
sndresponse defined in line 582; used 1 times

Defined variables

btable defined in line 35; used 3 times
dirbuf defined in line 46; used 11 times
dump defined in line 34; used 31 times
frommach defined in line 48; used 2 times
length defined in line 40; used 22 times
netd defined in line 36; used 5 times
publogfile defined in line 44; used 2 times
statbuf defined in line 45; used 20 times
status defined in line 37; used 25 times
tempfile defined in line 43; used 16 times

Defined macros

RENICE defined in line 30; used 2 times
nsecday defined in line 26; used 1 times
  • in line 28
numdays defined in line 28; used 2 times
Last modified: 1980-07-16
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2959
Valid CSS Valid XHTML 1.0 Strict