2BSD/src/net/net.c
/* Copyright (c) 1979 Regents of the University of California */
# include "defs.h"
/* must be setuid root */
/*
net - -c cmd -f -i file -l name -mmach -n -o file -p passwd
-r file -s file -w -x -y -z command
- take from standard input
-c cmd think of this as a "cmd" *
-f force prompting of user name and password
-i file remote stdin *
-l name remote login name
-m Mach remote machine
-n do not mail or write back anything, not even err msgs
-o file remote stdout & stderr *
-p pass remote password
-r file local response file
-s file local stdin file *
(super users only, always skip login/passwd check:)
-w this is a write/mail response cmd *
-x this is being forwarded through us to another machine *
-y skip login/password check *
-z this is a response file being returned *
* = not documented in net(NEW)
*/
static char dfname[]= DFNAME;
main(argc, argv)
char **argv; {
register int i;
int out();
char resp[FNS], infile[FNS], outfile[FNS], localin[FNS];
char buf[BFS*2];
char sin, code, zopt, wopt, yopt, xopt;
char *s;
long cnt = 0l;
char cflag = 'a';
FILE *file, *temp, *rfile;
struct utmp utmpstr;
argv[argc] = 0;
debugflg = DBV;
sin = 0;
cmd[0] = resp[0] = outfile[0] = infile[0] = 0;
realcmd[0] = localin[0] = 0;
wopt = xopt = yopt = zopt = 0;
ttystr[0] = 0;
if(isatty(0)) strcat(ttystr,ttyname(0));
else if(isatty(2)) strcat(ttystr,ttyname(2));
remote = 0;
signal(SIGHUP,out);
signal(SIGQUIT,out);
signal(SIGINT,out);
signal(SIGTERM,out);
while(argc > 1 && argv[1][0] == '-'){
argc--; argv++;
switch(argv[0][1]){
case 0: sin++; break;
case 'c': harg(realcmd,&argc,&argv); break;
case 'f': status.force++; break;
case 'i': harg(infile,&argc,&argv); break;
case 'l': harg(status.login,&argc,&argv); break;
case 'm': harg(buf,&argc,&argv); remote = lookup(buf); break;
case 'n': status.nowrite++; status.nonotify++; break;
case 'o': harg(outfile,&argc,&argv); break;
case 'p':
harg(status.mpasswd,&argc,&argv);
if(status.mpasswd[0] == 0)
strcpy(status.mpasswd,"\n\n");
break;
case 'r': harg(buf,&argc,&argv); addir(resp,buf); break;
case 's': harg(localin,&argc,&argv); break;
case 'w': wopt++; break;
case 'x': xopt++; break;
case 'y': yopt++; break;
case 'z': zopt++; break;
default:
fprintf(stderr,"Unknown option %s\n",argv[0]);
break;
}
}
while(argc > 1){
argc--; argv++;
strcat(cmd,argv[0]);
strcat(cmd," ");
}
code = 'q';
if(zopt || wopt || yopt || xopt){
/* check z or w or y or x option permission */
# ifndef TESTING
if(getuid() != 0){
error("Not super-user");
exit(1);
}
# endif
code = zopt ? 's' : 'w';
code = yopt ? 'y' : code;
if(status.mpasswd[0] == 0) /* no passwd required */
strcpy(status.mpasswd,"\n");
}
/*
code option reason
q normal request
w -w message to be written back
-x being forwarded through us
y -y simply skips login check (used by netlpr)
s -z normal response
*/
/*
debug("d:%s:%s:",status.defcmd,cmd);
*/
commandfile();
debug("d:%s:",cmd);
if(remote == 0)remote = getremote(local);
# ifndef TESTING
if(remote == local){
fprintf(stderr,"Request sent to local machine - doesn't make sense\n");
/* exit(1); */
}
# endif
strcat(status.defcmd," ");
if(strlen(cmd) == 0)strcpy(cmd,status.defcmd);
cmd[strlen(cmd)-1] = 0;
mktemp(dfname);
/* determine through machine */
i = gothru(local,remote);
if(i == 0){
s = longname(remote);
if(s != 0)fprintf(stderr,"No path to %s machine.\n",s);
else fprintf(stderr,"Unknown machine\n");
exit(1);
}
dfname[strlen(dfname)-11] = i; /* set directory */
dfname[strlen(dfname)-7] = i; /* set file (unused) */
if(resp[0]){
if(strcmp(resp,"/dev/tty") == 0){
error("Can't have /dev/tty as response file");
exit(1);
}
if(stat(resp,&statbuf) == -1){
strcpy(buf,resp);
s = &buf[0];
s = s + strlen(buf) - 1;
while(*s != '/' && s > &(buf[0]))s--;
*s = 0;
debug("chkdir %s",buf);
if(strlen(buf) == 0)strcpy(buf,".");
if(access(buf,2) == -1){
perror(buf);
exit(1);
}
if((rfile=fopen(resp,"w")) == NULL){
perror(resp);
exit(1);
}
chmod(resp,0600);
fclose(rfile);
chown(resp,getuid(),getgid());
}
else if(access(resp,2) == -1){
perror(resp);
exit(1);
}
}
file = fopen(dfname,"w");
if(file == NULL){
perror(dfname);
exit(1);
}
chmod(dfname,0600);
chown(dfname,getuid(),getgid());
if(xopt)goto stickit;
if(code == 'q'){
passwdent();
promptlogin();
}
if(status.mpasswd[0] == '\n')
status.mpasswd[0] = 0;
# ifdef OLDPROT
if(machtype[local-'a'] == M_CC && machtype[remote-'a'] == M_CC
&& status.mpasswd[0] != 0){
s = crypt(status.mpasswd);
strcpy(status.mpasswd,s);
}
# endif
if(status.mpasswd[0] == 0 && code == 'q' &&
strcmp(status.login,"network") != 0){
fprintf(stderr,"Zero-length password not allowed\n");
unlink(dfname);
exit(1);
}
if(code == 'q' && (streql(status.login,"root") == 0 ||
streql(status.login,"ruut") == 0)){
fprintf(stderr,"Can't login as root through the network\n");
unlink(dfname);
exit(1);
}
# ifdef SPACCT
/* handle special accounts */
strcpy(status.mpasswd,handlesp(status.login,status.mpasswd,
status.localname,status.muid,status.mgid));
# endif
enmask(status.mpasswd);
ltime = 0;
if(ttystr[0] && status.nowrite == 0){
temp = fopen("/etc/utmp","r");
if(temp == NULL){
perror("/etc/utmp");
unlink(dfname);
exit(1);
}
while(fread(&utmpstr,1,sizeof utmpstr,temp) == sizeof utmpstr)
# ifdef OLDTTY
if(utmpstr.ut_tty == ttystr[8]){
# else
if(strcmp(utmpstr.ut_line,ttystr+5) == 0){
# endif
ltime = utmpstr.ut_time;
break;
}
}
/*
debug("p:%s:\n",status.mpasswd);
*/
if(status.nonotify)cflag += F_NONOTIFY;
/*
protocol:
code, remote mach, local mach, version stamp (2), remote login name,
password, -i, -o, -r files, local login name, terminal, flag,
utmp tty time, cc jobno, unused string,
command '\n' real command '\n'
any data
changes:
1) remove header
2) remove unused string
3) use ascii length instead of 4 bytes
4) encrypt the login name, command, and part of data as well
*/
fprintf(file,
"%c :%c :%c :%c :%c :%s :%s :%s :%s :%s :%s :%s :%c :%lo :%d :%ld :",
code,remote,local,VMAJOR+'a',VMINOR+'a',status.login,
status.mpasswd,infile,outfile,resp,
status.localname,ttystr,cflag,ltime,
status.jobno,gettime()-TIMEBASE);
fputs(cmd,file);
putc('\n',file);
fputs(realcmd,file);
putc('\n',file);
stickit:
if(sin)
while((i = fread(buf,1,BUFSIZ,stdin)) > 0){
if(fwrite(buf,1,i,file) != i){
perror("net queue file");
unlink(dfname);
exit(1);
}
if((cnt += i) > MAXFILE)goto toobig;
if(feof(stdin))break;
}
else if(localin[0]){
if(access(localin,4) == -1){
perror(localin);
unlink(dfname);
exit(1);
}
temp = fopen(localin,"r");
if(temp == NULL){
perror(localin);
unlink(dfname);
exit(1);
}
while((i = fread(buf,1,BUFSIZ,temp)) > 0){
if((cnt += i) > MAXFILE)goto toobig;
if(fwrite(buf,1,i,file) != i){
perror("net queue file");
unlink(dfname);
exit(1);
}
}
fclose(temp);
}
fclose(file);
chmod(dfname,0400);
dfname[strlen(dfname)-9] = 'c';
file = fopen(dfname,"w");
chmod(dfname,0400);
fclose(file);
chown(dfname,getuid(),getgid());
exit(0);
toobig:
fprintf(stderr,"No more than %ld bytes can be sent\n",MAXFILE);
out(); /* no return */
}
out(){
register int i;
struct sgttyb stt;
signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN);
signal(SIGQUIT,SIG_IGN); signal(SIGTERM,SIG_IGN);
unlink(dfname);
i = strlen(dfname) - 9;
dfname[i] = (dfname[i] == 'c' ? 'd' : 'c');
unlink(dfname);
if(gtty(0,&stt) >= 0){
stt.sg_flags |= ECHO;
stty(0,&stt);
}
exit(1);
}
enmask(s)
register char *s; {
# ifdef OLDPROT
while(*s){
*s &= 0177; /* strip quote bites */
*s++ ^= 040; /* invert upper-lower */
}
# else
static char buf[20];
strcpy(s,nbsencrypt(s,THEKEY,buf));
# endif
}
addir(s,t)
register char *s, *t; {
if(t[0] == '/')strcpy(s,t);
else {
gwd(s);
strcat(s,t);
}
}
/* returns pass if not special, otherwise returns funny passwd */
/* list of special accounts must be consistent - with netdaemon.c */
char *handlesp(log,pass,localname,luid,lgid)
char *log,*pass,*localname;{
# ifdef SPACCT
long lt;
char str[20];
if(strcmp(log,localname) == 0 && luid != 0 && lgid == 0 && (
strcmp(log,"source") == 0
|| strcmp(log,"daemon") == 0
)) {
lt = lgid;
lt = (lt << 16) | luid;
sprintf(str,"%ld",lt);
return(str);
}
# endif
return(pass);
}