/* Copyright (c) 1979 Regents of the University of California */
/* must be setuid root */
/* netdaemon mach readfd writefd */
static char header
[] = "ABCDE";
FILE *temp
, *dir
, *jfile
;
char resp
[FNS
], infile
[FNS
], outfile
[FNS
];
static char tempfile
[]= TEMPFILE
;
static char publogfile
[]= PUBLOGFILE
;
static char dumpfile
[]= DUMPFILE
;
static char namefile
[]= NAMEFILE
;
signal(SIGTERM
,handlekill
);
/* now running alone as a daemon */
for(i=0; i<15; i++)close(i);
senddir
[strlen(senddir
)-1] = remote
; /* choose dir */
dir
= fopen(senddir
,"r");
tempfile
[strlen(tempfile
) - 7] = remote
;
sprintf(buf
,"net restarted to %s %d %s",longname(remote
),
dump
.longtime
= dump
.shorttime
= ltime
;
if(!debugflg
)fclose(stderr
);
for(;;){ /* begin reading file */
debug("daemon %c %d\nreceive",remote
,getpid());
nsendfail
= 0; /* it sent, it is up */
dump
.waittot
+= dump
.waittime
;
if(i
== -1)dump
.nabnormal
++;
if(t
- dump
.shorttime
> SAMPL
)pload(t
);
if(t
- dump
.longtime
> BIGSAMPL
)dumpit(t
);
/* count up to NSEND, sending, then wait NSEND */
if(nsendfail
>= NSEND
*2)nsendfail
= 0;
static long lasttime
= 0;
if(stat(senddir
,&statbuf
) < 0){
error("%s %s",senddir
,sys_errlist
[errno
]);
if(statbuf
.st_mtime
== lasttime
&& nleft
== 0)return; /* no need to search */
lasttime
= statbuf
.st_mtime
;
while(fread(&dirbuf
,1,sizeof dirbuf
,dir
) == sizeof dirbuf
){
|| dirbuf
.d_name
[0] != 'c'
|| dirbuf
.d_name
[1] != 'f'
|| dirbuf
.d_name
[2] != remote
|| stat(dirbuf
.d_name
,&statbuf
) < 0)
if(stat(dirbuf
.d_name
,&statbuf
) < 0)continue;
filesize
= getsize(&statbuf
);
if(jsize
== -1 || jsize
> filesize
){
jname
[i
] = dirbuf
.d_name
[i
];
jusr
= guid(statbuf
.st_uid
,statbuf
.st_gid
);
addtolog(remote
,"^S %s %c: %s ",p
,remote
,jname
+2);
dump
.waittot
+= dump
.waittime
;
filesize
= getsize(&statbuf
);
tt
= comptime(ot
- statbuf
.st_mtime
);
addtolog(remote
,"^T%c(%s, %ldb, %ldsec, %4.1fb/sec, w %s)\n",
remote
,s
,filesize
, diff
,r
, tt
);
addtopublic("%s: sent to %s: %s (%s, %ld bytes, wait %s)\n",
s
,longname(remote
), p
,jname
+3,filesize
,tt
);
dump
.bytetot
+= filesize
;
send(){ /* push those bytes */
/* returns 0 if send fails, 1 otherwise */
if(stat(jname
,&statbuf
) < 0)goto sfail
;
lsize
= getsize(&statbuf
);
if(lsize
< MINSIZE
){ /* all files are at least this long */
jfile
= fopen(jname
,"r");
if(jfile
== NULL
)goto sfail
;
lsize
= fixuplong(lsize
);
if(xwrite(mbuf
,1,i
) == WRITEFAIL
)goto bwrite
;
while((n
=fread(buf
,1,BLOCKSIZE
,jfile
)) > 0)
if(xwrite(buf
,1,n
) == WRITEFAIL
)goto bwrite
;
addtolog(remote
,"^F%c ",remote
);
error("%s: %s",jname
,sys_errlist
[errno
]);
/* returns -2 in normal fail, -1 in abnormal fail, >= 0 otherwise */
long timesent
,otime
,olength
,diff
,rcvfinish
,nt
;
n
= nread(hbuf
,1,strlen(header
));
if(n
== BROKENREAD
)return(-2);
if(n
!= strlen(header
) || strcmp(header
,hbuf
) != 0){
error("wrong head %d %s",n
,hbuf
);
if(n
== BROKENREAD
)return(-2);
error("bad length nread %d",n
);
length
= fixuplong(length
);
debug("length = %ld\n",length
);
if(tmach
< 'a' || 'z' < tmach
){
if(tmach
!= local
)goto forw
; /* being forwarded through us */
i
+= mgets(status
.login
);
i
+= mgets(status
.mpasswd
);
i
+= mgets(status
.localname
);
if(ttystr
[0] == 0)strcpy(ttystr
,"/dev/ttyx");
if(!fmach
|| !code
|| !cflag
|| !vmajor
|| !vminor
){
if(vmajor
!= VMAJOR
|| vminor
!= VMINOR
){
error("versions dont agree (%d,%d) vs. (%d,%d) remote",
VMAJOR
,VMINOR
,vmajor
,vminor
);
sscanf(buf
,"%lo",<ime
);
status
.jobno
= atoi(buf1
);
i
+= mgets(buf1
); /* time sent */
sscanf(buf1
,"%ld",×ent
);
if(i
!= 0){error("mgets fails"); return(-1);}
if(realcmd
[0] == 0)strcpy(realcmd
,cmd
);
while(*s
&& *s
!= ' ')s
++;
if(strcmp(realcmd
,"netlpr") == 0)dump
.nnetlpr
++;
else if(strcmp(realcmd
,"netmail") == 0)dump
.nnetmail
++;
else if(strcmp(realcmd
,"mail") == 0)dump
.nsmail
++;
else if(strcmp(realcmd
,"netcp") == 0)dump
.nnetcp
++;
else if(strcmp(realcmd
,"response") == 0)dump
.nresp
++;
debug("%c %c %c (%c,%c) %s %s %s %s (%s) %s %c %lo %d %s\n",
code
,tmach
,fmach
,vmajor
+'a',vminor
+'a',status
.login
,
infile
,outfile
,resp
,status
.localname
,
ttystr
,cflag
+'a',ltime
,status
.jobno
,cmd
);
/* any chars left are data */
if(length
> 0){ /* make a temp input file */
temp
= fopen(tempfile
,"w");
error("%s %s",tempfile
,sys_errlist
[errno
]);
if(tmach
!= local
)fprintf(temp
,"%c :%c :",code
,tmach
);
while((n
= mread(buf
,1,BLOCKSIZE
)) > 0)
if(fwrite(buf
,1,n
,temp
) != n
){
error("%s %s",tempfile
,sys_errlist
[errno
]);
if(n
== BROKENREAD
|| length
> 0){
diff
= gettime() - otime
;
addtolog(remote
,"^P(to %c, %ldb, %ldsec, %4.1fb/sec)\n",
sprintf(buf
,"-m%c",tmach
);
execl(netcmd
,"net","-x","-s",tempfile
,buf
,0);
if(length
> 0){error("file too short"); return(-1); }
while((i
=fork())== -1)sleep(2);
if(i
> 0){wait(&dummy
); return(1);} /* normal return */
while((i
=fork())== -1)sleep(2);
/* child process which forks and waits */
while((i
=fork())== -1)sleep(2);
strcpy(status
.loginshell
,Bsh
);
n
= check(status
.login
,status
.mpasswd
,(code
== 'q'));
if(!n
)errormsg(fmach
,"Bad remote login/password %s",status
.login
);
temp
= fopen(resfile
,"w");
errormsg(fmach
,"creat %s %s",resfile
,sys_errlist
[errno
]);
chown(resfile
,status
.muid
,status
.mgid
);
if(sin
)chown(tempfile
,status
.muid
,status
.mgid
);
if((i
=getuid()) != status
.muid
)error("setuid fails");
/* check for allowed root commands, for security reasons */
while(*s
&& *s
!= ' ')s
++;
/* these are the only commands root may execute */
if(strcmp(cmd
,"cat") != 0
&& strcmp(cmd
,writecmd
) != 0
&& strcmp(cmd
,"/usr/lib/tq") != 0
&& strcmp(cmd
,"/usr/lib/rtrrm") != 0
&& strcmp(cmd
,"lpr") != 0)
errormsg(fmach
,"Not allowed to use that command as root");
if(chdir(status
.dir
) < 0)
errormsg(fmach
,"chdir %s %s",status
.dir
,sys_errlist
[errno
]);
setenv(status
.dir
); /* set up v7 environment */
if(sin
)mreopen(fmach
,tempfile
,"r",stdin
);
else if(infile
[0])mreopen(fmach
,infile
,"r",stdin
);
else mreopen(fmach
,"/dev/null","r",stdin
);
if(code
== 's' && outfile
[0]){
if(stat(outfile
,&statbuf
) < 0
|| getsize(&statbuf
) != 0
|| !(statbuf
.st_mode
&0600))
errormsg(local
,"bad result file %s",outfile
);
mreopen(fmach
,outfile
,"w",stdout
);
temp
= fopen(outfile
,"w");
errormsg(fmach
,"fopen %s %s",outfile
,sys_errlist
[errno
]);
mreopen(fmach
,outfile
,"w",stdout
);
else mreopen(fmach
,resfile
,"a",stdout
);
debug("exec '%s'\n",cmd
);
mreopen(fmach,resfile,"a",stderr);
for(i
=3;i
<15;i
++)close(i
);
mexecl(status
.loginshell
,"sh","-c",cmd
,0);
} while(errno
== ETXTBSY
);
if(code
== 'q' && (resp
[0] || !(cflag
&F_NONOTIFY
))){
/* send response back if a response file
was given or if mail/write is allowed */
/* should give an error message for
if(stat(resfile
,&statbuf
) < 0){
error("%s %s",resfile
,sys_errlist
[errno
]);
if(getsize(&statbuf
) >= MAXFILE
){
errormsg(fmach
,"Result file too large - not sent");
if(getsize(&statbuf
) == 0 && resp
[0])goto next
;
if(resp
[0])sprintf(buf1
,"-o %s cat",resp
);
else sprintf(buf1
,"%s %s %s %lo %c %s \"'%s'\" %ld",writecmd
,
status
.localname
,ttystr
,ltime
,tmach
,status
.login
,
sprintf(buf
,"%s -m%c -z -n -l %s -s %s -c response %s",
netcmd
,fmach
,status
.localname
,resfile
,buf1
);
dummy
= system(buf
); /* execute command buf */
diff
= rcvfinish
- otime
;
sprintf(buf
,"%s rcv %s: %s (%s)",
s
,longname(fmach
),status
.login
,status
.localname
);
addtolog(remote
,"%s C: %s\n",buf
,realcmd
);
addtopublic("%s R: %d C: %s\n",buf
,rcode
>>8,realcmd
);
nt
= rcvfinish
- timesent
- TIMEBASE
;
if(nt
> 0L)sprintf(buf
," took (%s,%ld)",comptime(nt
),nt
);
addtolog(remote
,"\t\tR: %d%s %ldb %ldsec %4.1fb/sec\n",
rcode
>>8,buf
,olength
,diff
,r
);
verify = 1 if password must check */
check(l
,pass
,verify
) /* 1 if OK, 0 if not */
char *s
, *u
, *nullstr
= "";
ver
= (verify
== 0); /* ver is true if password verification
if(l
[0] == 0)return(ver
);
if(!goodacctname(l
))return(ver
);
if(pwd
== NULL
)return(ver
);
if(machtype
[local
-'a'] == M_CC
&& machtype
[frommach
-'a'] == M_CC
)
if(*pass
)s
= crypt(pass
,pwd
->pw_passwd
);
status
.muid
= guid(pwd
->pw_uid
,pwd
->pw_gid
);
status
.mgid
= pwd
->pw_gid
;
if(isdigit(pwd
->pw_gecos
[0]))status
.jobno
= atoi(pwd
->pw_gecos
);
else status
.jobno
= 32767;
strcpy(status
.dir
,pwd
->pw_dir
);
strcpy(status
.loginshell
,pwd
->pw_shell
);
if(u
[0] == 0 /* || strcmp("sh",u+strlen(u)-2) != 0 */) strcpy(u
,Bsh
);
/* ignore network passwd */
if(!spacct(status
.login
,s
,status
.localname
,status
.muid
,status
.mgid
)
&& strcmp(pwd
->pw_passwd
,s
) && verify
)
if(length
<= 0)return(0);
if(length
< n
)n
= length
;
if(n
!= BROKENREAD
)length
-= n
;
char mgetc(){ /* returns 0 if fail */
if((n
=nread(buf
,1,3)) == BROKENREAD
)return(0);
if(n
!= 3){error("bad read %d",n
); return(0); }
if(buf
[1] != ' ' && buf
[1] != ':'){error("Bad char %c",buf
[1]); return(0); }
if(length
< 0){error("length wrong2 %ld",length
); return(0); }
mgets(s
) /* returns 0 if ok, 1 if not */
if((n
=nread(&c
,1,1)) == BROKENREAD
){
if((n
=nread(&c
,1,1)) == BROKENREAD
){
if(nread(&c
,1,1) == BROKENREAD
){
if(length
< 0){error("length wrong1 %ld %s",length
,q
); return(-1); }
mgetcmd(s
) /* returns 0 if succeed, 1 otherwise */
if((n
=nread(&c
,1,1)) == BROKENREAD
){
if(n
<= 0 || c
== '\n')break;
if(nread(&c
,1,1) == BROKENREAD
){
if(s
[i
] < '0' || s
[i
] > '9'){
static long out
= 0L, ocut
= 0L, ost
= 0L, ocst
= 0L;
elapt
= currt
- dump
.shorttime
;
u
= tbf
.tms_utime
-out
+ tbf
.tms_cutime
-ocut
;
s
= tbf
.tms_stime
-ost
+ tbf
.tms_cstime
-ocst
;
if(elapt
> 0)r
= (r
/elapt
)*100.0;
/* adjust to be seconds */
str
[strlen(str
) - 5] = 0;
sprintf(buf
,"%s (%s):\t%4.1fu\t%4.1fs\t%5.2f\t%s\n",
str
,longname(remote
),ru
,rs
,r
,comptime(elapt
));
addtodump(remote
,"%s",buf
);
if(dump
.elaptot
> 0)br
= br
/dump
.elaptot
;
addtodump(remote
, "\tTrans.\t%.6ld bytes\t%4.1f bytes/sec\t%s",
dump
.bytetot
,br
,comptime(dump
.elaptot
));
addtodump(remote
," %s\n",comptime(dump
.waittot
));
dump
.waittot
= dump
.elaptot
= dump
.bytetot
= 0L;
sprintf(buf
,"%s %c",NETQSTAT
,remote
);
system(buf
); /* gather stats on netq len. */
register struct dumpstruc
*p
= &dump
;
elapt
= currt
- dump
.longtime
;
r
= dump
.outime
+ dump
.ostime
;
if(elapt
> 0)r
= (r
/elapt
) * 100.0;
dump
.longtime
= dump
.shorttime
;
ntot
= p
->nnetcp
+ p
->nnetmail
+ p
->nsmail
+ p
->nnetlpr
addtodump(remote
,"Daily statisics\t(%s):\nSummary:\n",tt
);
addtodump(remote
,"\t# sent %d\t# pass-thru %d\t# rcv %d:\t# netcp %d\n",
p
->nsend
,p
->npass
,ntot
,p
->nnetcp
);
addtodump(remote
,"\t# netlpr %d\t# netmail %d\t# sendmail %d\t# resp %d\n",
p
->nnetlpr
,p
->nnetmail
,p
->nsmail
,p
->nresp
);
addtodump(remote
,"Protocol summary:\n");
addtodump(remote
,"\t# pk sent %d\t# pk rcv %d\t# b sent %ld\t# b rcv %ld\n",
p
->npacksent
,p
->npackrcv
,p
->nbytesent
, p
->nbytercv
);
"\t# send fails %d\t# retrans %d\t# abn %d\t\t# cksum errs %d\n",
p
->nsendfail
,p
->nretrans
, p
->nabnormal
,p
->ncksum
);
addtodump(remote
,"Load:\t\t\t\t%4.1fu\t%4.1fs\t%5.2f%%\t%s\n",
ru
,rs
,r
,comptime(elapt
));
p
->nbytesent
= p
->nbytercv
= p
->outime
= p
->ostime
= 0L;
p
->nretrans
= p
->nloop
= p
->nabnormal
= p
->ncksum
= 0;
p
->npacksent
= p
->npackrcv
= p
->nnetcp
= p
->nnetmail
= 0;
p
->nsmail
= p
->nnetlpr
= p
->nnet
= p
->npass
= 0;
p
->nsend
= p
->nsendfail
= 0;
/* returns 1 if n is ok, 0 if not */
if(strcmp(btable
[i
].bname
,n
) == 0 &&
local
== btable
[i
].bmach
)return(0);
*s
&= 0177; /* strip quote bites */
*s
++ ^= 040; /* invert upper-lower */
strcpy(s
,nbsdecrypt(s
,THEKEY
,buf
));
/* simply handles errors by giving error msg */
if(freopen(a
,b
,c
) == NULL
)errormsg(f
,"%s: %s",a
,sys_errlist
[errno
]);
addtopublic(s
,a
,b
,c
,d
,e
,f
,g
,h
,i
,j
,k
,l
,m
,n
)
if(stat(publogfile
,&statbuf
) < 0)return;
log
= fopen(publogfile
,"a");
fprintf(log
,s
,a
,b
,c
,d
,e
,f
,g
,h
,i
,j
,k
,l
,m
,n
);
addtodump(mach
,str
,a
,b
,c
,d
,e
,f
,g
,h
,i
,j
,k
,l
,m
,n
,o
,p
,q
,r
,t
,u
)
dumpfile
[strlen(dumpfile
)-1] = mach
;
if(stat(dumpfile
,&statbuf
) < 0)return;
log
= fopen(dumpfile
,"a");
fprintf(log
,str
,a
,b
,c
,d
,e
,f
,g
,h
,i
,j
,k
,l
,m
,n
,o
,p
,q
,r
,t
,u
);
/* set up a dummy environment for v7 /bin/sh */
static char *env
[3],benv
[2][50];
strcpy(env
[0],"PATH=:/bin:/usr/bin");
sprintf(env
[1],"HOME=%s",home
);
/* errormsg- sends error message to user-
may be on local or remote machine */
errormsg(fmach
,s
,a
,b
,c
,d
,e
,f
,g
,h
)
/* can't use -w,-x,-y,-z because must be root for those */
char buf
[BFS
*2], buf1
[BFS
*2];
if(fmach
< 'a' || 'z' < fmach
)fmach
= local
;
if(ttystr
[0] == 0)strcpy(ttystr
,"/dev/ttyx");
if(fmach
== local
&& status
.login
[0])
strcpy(status
.localname
,status
.login
);
if(status
.localname
[0] == 0)strcpy(status
.localname
,status
.login
);
if(status
.localname
[0] == 0 || strcmp(status
.localname
,"root") == 0)
strcpy(status
.localname
,"schmidt");
/* will send to localname on fmach machine */
/* in case of error, send to "schmidt" */
/* error messages should never be sent to root */
sprintf(buf
,"Error: Cmd: %s Message: ",realcmd
);
sprintf(buf1
,s
,a
,b
,c
,d
,e
,f
,g
,h
);
sprintf(buf1
, "echo \"%s\" | %s %s %s %lo %c %s",
buf
,writecmd
,status
.localname
,ttystr
,ltime
,local
,status
.login
);
"echo \"%s\" | %s -m%c -n -c response -l network -p \"\" - %s %s %s %lo %c %s",
buf
,netcmd
,fmach
,writecmd
,status
.localname
,ttystr
,ltime
,local
,status
.login
);
handlekill(){ /* SIGTERM signal */
addtodump(remote
,"Netdaemon terminated.\n");
exit(0); /* kill myself */
spacct(log
,pass
,localname
,luid
,lgid
) /* returns 1 if login ok, 0 if not */
char *log
,*pass
,*localname
; {
if(strcmp(log
,"network") == 0)return(1);
if(strcmp(log
,localname
) == 0 && luid
!= 0 && lgid
== 0
strcmp(log
,"source") == 0
|| strcmp(log
,"daemon") == 0)
/* login name is same on both machines, userid is group 0,
non-root, the password is numeric
and the login name is one of a select few */
if((luid
== u
) && (lgid
== g
))return(1);
/* add the user's name to our name list */
strcmp(name
,"root") == 0 ||
strcmp(name
,"network") == 0 ||
strcmp(name
,"schmidt") == 0)return;
if(stat(namefile
,&statbuf
) < 0)return;
log
= fopen(namefile
,"a");
fprintf(log
,"%s:%s\n",longname(local
),name
);