BSD 4_1_snap release
[unix-history] / usr / src / cmd / berknet / net.c
/* sccs id variable */
static char *net_sid = "@(#)net.c 1.8";
# include "defs.h"
/* must be setuid root */
/*
net - -b -c cmd -f -i file -l name -mmach -n -o file -p passwd
-r file -s file -u uid -w -x -y -z command
- take from standard input
-b never send anything back
-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 write back anything, always mail them back
-o file remote stdout & stderr *
-p pass remote password
-q quiet option, send back only if rcode !=0 or if there is stdout
-r file local response file
-s file local stdin file *
(super users only, always skip login/passwd check:)
-u uid net queue files should be owned by uid (16 bits)
-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)
*/
/*
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
*/
/* global variables */
struct userinfo status;
/* local variables */
static char dfname[]= DFNAME;
main(argc, argv)
char **argv; {
register int i;
int outerror(),uid;
char localin[FNS], skey[30];
char buf[BUFSIZ], suid[10];
char sin =0, zopt = 0, wopt = 0, yopt = 0, xopt = 0;
char *s,**sargv;
long cnt = 0L, maxfile = MAXFILELARGE;
FILE *file, *temp, *rfile;
struct utmp *putmp;
struct stat statbuf;
struct header hd;
debugflg = DBV;
hd.hd_scmdact[0] = hd.hd_srespfile[0] = hd.hd_soutfile[0] = 0;
hd.hd_sinfile[0] = hd.hd_scmdvirt[0] = hd.hd_sttyname[0] = 0;
localin[0] = 0;
suid[0] = 0;
sargv = argv;
if(isatty(0)) strcat(hd.hd_sttyname,ttyname(0));
else if(isatty(2)) strcat(hd.hd_sttyname,ttyname(2));
remote = 0;
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
signal(SIGHUP, outerror);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, outerror);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, outerror);
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
signal(SIGTERM, outerror);
while(argc > 1 && argv[1][0] == '-'){
argc--; argv++;
switch(argv[0][1]){
case 0:
sin++;
break;
case 'b':
status.nonotify++;
break;
case 'c':
harg(hd.hd_scmdvirt);
break;
case 'f':
status.force++;
break;
case 'i':
harg(hd.hd_sinfile);
break;
case 'l':
harg(status.login);
break;
case 'm':
harg(buf);
remote = lookup(buf);
if(remote == 0){
fprintf(stderr,"Unknown machine %s\n",buf);
exit(EX_NOHOST);
}
break;
case 'n':
status.nowrite++;
break;
case 'o':
harg(hd.hd_soutfile);
break;
case 'p':
harg(status.mpasswd);
if(status.mpasswd[0] == 0)
strcpy(status.mpasswd,"\n\n");
break;
case 'q':
status.quiet++;
break;
case 'r':
harg(buf);
addir(hd.hd_srespfile,buf);
break;
case 's':
harg(localin);
break;
case 'u':
harg(suid);
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(hd.hd_scmdact,argv[0]);
strcat(hd.hd_scmdact," ");
}
sargv[1] = 0; /* so ps won't show passwd ??? */
hd.hd_uidfrom = uid = getuid();
hd.hd_gidfrom = getgid();
hd.hd_code = 'q';
if(zopt || wopt || yopt || xopt || suid[0] != 0){
/* check z or w or y or x option permission */
# ifndef TESTING
/* check effective user id ?? */
if (uid != SUPERUSER && uid != NUID) {
fprintf(stderr, "Error: Not super-user\n");
fprintf(stderr,"zopt %d wopt %d yopt %d xopt %d suid[0] %s\n", zopt, wopt, yopt, xopt, suid);
fprintf(stderr,"uid %d\n", uid);
debugflg = 1;
printhd(&hd);
outerror(EX_UNAVAILABLE);
}
# endif
hd.hd_code = zopt? 's': 'w';
hd.hd_code = yopt? 'y': hd.hd_code;
if (status.mpasswd[0] == 0) /* no passwd required */
strcpy(status.mpasswd, "\n");
debug("zopt %d wopt %d yopt %d xopt %d suid[0] %s\n", zopt, wopt, yopt, xopt, suid);
debug("uid %d\n", uid);
if(xopt)
setuid(SUPERUSER);
}
#ifdef CRN
strcpy( status.jobno, MAGICCRN ); /* default (invalid) crn */
#else
strcpy( status.jobno, "XYZZ"); /* default (invalid) crn */
#endif
if(hd.hd_code == 'q' && !xopt){
/* read passwd file, get status.localname & crn */
passwdent();
}
/* sets remote,status.login,status.force,status.mpasswd,
status.nonotify, status.nowrite */
/* may read passwd file if getenv(HOME) reads it */
commandfile();
if(status.force)status.login[0] = status.mpasswd[0] = 0;
/* look up login name and passwd in the environment */
envloginpasswd(remote,status.login,status.mpasswd);
if(remote == 0)remote = getremote(local);
# ifndef TESTING
if(remote == local){
fprintf(stderr,"Request sent to local machine - doesn't make sense\n");
/* outerror(); */
}
# endif
strcat(status.defcmd," ");
if(strlen(hd.hd_scmdact) == 0)strcpy(hd.hd_scmdact,status.defcmd);
hd.hd_scmdact[strlen(hd.hd_scmdact)-1] = 0;
do {
mktemp(dfname); /* make until unique!! */
} while(stat(dfname,&statbuf) >= 0);
/* 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");
outerror(EX_NOHOST);
}
dfname[strlen(dfname)-11] = i; /* set directory */
dfname[strlen(dfname)-7] = i; /* set file (unused) */
/* check to see if data files are directories */
if(isdirectory(hd.hd_srespfile) || isdirectory(hd.hd_sinfile) || isdirectory(hd.hd_soutfile)){
fprintf(stderr,"%s is a directory, must be a file\n",
isdirectory(hd.hd_srespfile) ? hd.hd_srespfile :
isdirectory(hd.hd_sinfile) ? hd.hd_sinfile :
hd.hd_soutfile);
outerror(EX_USAGE);
}
if(suid[0] != 0)uid = atoi(suid);
if(hd.hd_srespfile[0]){
if(strcmp(hd.hd_srespfile,"/dev/tty") == 0){
fprintf(stderr,"Can't have /dev/tty as response file.\n");
outerror(EX_USAGE);
}
if(stat(hd.hd_srespfile,&statbuf) == -1){
strcpy(buf,hd.hd_srespfile);
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);
outerror(EX_USAGE);
}
if((rfile=fopen(hd.hd_srespfile,"w")) == NULL){
perror(hd.hd_srespfile);
outerror(EX_USAGE);
}
chmod(hd.hd_srespfile,0600);
fclose(rfile);
mchown(hd.hd_srespfile,uid,hd.hd_gidfrom);
}
else if(access(hd.hd_srespfile,2) == -1){
perror(hd.hd_srespfile);
outerror(EX_USAGE);
}
else if(getsize(&statbuf) != 0L){
fprintf(stderr,"%s must have 0-length or not exist\n",
hd.hd_srespfile);
outerror(EX_USAGE);
}
}
/* go ahead and prompt for login name and passwd, if neccessary,
as long as the X option has not been specified */
if(hd.hd_code == 'q' && !xopt)promptlogin(remote);
/* at this point, we create the dfa... file */
file = fopen(dfname,"w");
if(file == NULL){
perror(dfname);
outerror(EX_OSERR);
}
chmod(dfname,0600);
mchown(dfname,uid,getgid());
if(xopt)goto stickit;
if(status.mpasswd[0] == '\n')
status.mpasswd[0] = 0;
if(status.mpasswd[0] == 0 && hd.hd_code == 'q' &&
strcmp(status.login,"network") != 0){
fprintf(stderr,"Zero-length password not allowed\n");
outerror(EX_USAGE);
}
if(hd.hd_code == 'q' && (streql(status.login,"root") == 0 ||
streql(status.login,"ruut") == 0)){
fprintf(stderr,"Can't login as root through the network\n");
outerror(EX_USAGE);
}
makeuukey(skey,status.login,remote);
nbsencrypt(status.mpasswd,skey,hd.hd_sencpasswd);
enmask(status.mpasswd);
hd.hd_lttytime = 0;
if(hd.hd_sttyname[0] && status.nowrite == 0){
putmp = getutmp(hd.hd_sttyname);
if(putmp != NULL) hd.hd_lttytime = putmp->ut_time;
}
/*
debug("p:%s:\n",status.mpasswd);
*/
/* write the header info onto 'file' */
hd.hd_mchto = remote;
hd.hd_mesgid.msg_mch = hd.hd_mchfrom = local;
hd.hd_vmajor = VMAJOR;
hd.hd_vminor = VMINOR;
strcpy(hd.hd_snto,status.login);
strcpy(hd.hd_snfrom,status.localname);
strcpy(hd.hd_spasswd,status.mpasswd);
strcpy(hd.hd_ijobno, status.jobno );
hd.hd_mesgid.msg_ltime = hd.hd_ltimesent = gettime();
hd.hd_fquiet = status.quiet;
hd.hd_fnonotify = status.nonotify;
hd.hd_mesgid.msg_pid = getpid();
hd.hd_fcompressed = 0;
/* handle account pairs, accounts which do not require
a passwd if you are logged in on the same one here */
hd.hd_facctpair = fisacctpair(&hd);
writehdfd(&hd,file);
printhd(&hd);
stickit:
if(sin)
while((i = fread(buf,1,BUFSIZ,stdin)) > 0){
if(fwrite(buf,1,i,file) != i){
perror("net queue file");
outerror(EX_OSFILE);
}
if((cnt += i) > maxfile)goto toobig;
if(feof(stdin))break;
}
else if(localin[0]){
if(access(localin,4) == -1){
perror(localin);
outerror(EX_OSFILE);
}
temp = fopen(localin,"r");
if(temp == NULL){
perror(localin);
outerror(EX_OSFILE);
}
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");
outerror(EX_OSFILE);
}
}
fclose(temp);
}
fclose(file);
chmod(dfname,0400);
dfname[strlen(dfname)-9] = 'c';
file = fopen(dfname,"w");
chmod(dfname,0400);
fclose(file);
mchown(dfname,uid,getgid());
exit(EX_OK);
toobig:
fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile);
outerror(EX_USAGE); /* no return */
}
/*
called if there is an error, makes sure that the files created
are deleted and the terminal is reset to echo
*/
outerror(ret){
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(ret);
}
enmask(s)
register char *s; {
while(*s){
*s &= 0177; /* strip quote bites */
*s++ ^= 040; /* invert upper-lower */
}
}
addir(s,t)
register char *s, *t; {
if(t[0] == '/')strcpy(s,t);
else {
gwd(s);
strcat(s,t);
}
}
/* returns true if phd is an account pair, false otherwise */
fisacctpair(phd)
register struct header *phd;
{
return(0);
}
static struct stat x;
static struct direct y;
static FILE *file;
static int off = -1;
/* these three routines gwd, cat, ckroot and
data structures x, y, off, do a pwd to string name */
#ifdef V6
gwd(name)
register char *name; {
*name = 0;
for(;;){
stat(".",&x);
if((file = fopen("..","r")) == NULL)break;
do {
if(fread(&y,1,sizeof y,file) != sizeof y)break;
} while(y.d_ino != x.st_ino);
fclose(file);
if(y.d_ino == ROOTINO){
ckroot(name);
break;
}
if(cat(name))break;
chdir("..");
}
chdir(name);
}
ckroot(name)
char *name; {
register int i;
if(stat(y.d_name,&x) < 0)return;
i = x.st_dev;
if(chdir("/") < 0)return;
if((file = fopen("/","r")) == NULL)return;
do {
if(fread(&y,1,sizeof y,file) != sizeof y)return;
if(y.d_ino == 0)continue;
if(stat(y.d_name,&x) < 0)return;
} while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR);
if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0)
if(cat(name))return;
i = strlen(name);
name[i+1] = 0;
while(--i >= 0)name[i + 1] = name[i];
name[0] = '/';
return;
}
#else
static struct stat xx;
gwd(name)
register char *name; {
int rdev, rino;
register int i;
*name = 0;
stat("/", &x);
rdev = x.st_dev;
rino = x.st_ino;
for (;;) {
stat(".", &x);
if (x.st_ino == rino && x.st_dev == rdev)
break;
if ((file = fopen("..", "r")) == NULL)
break;
fstat(fileno(file), &xx);
chdir("..");
if (x.st_dev == xx.st_dev) {
if (x.st_ino == xx.st_ino)
break;
do
if (fread((char *)&y, 1, sizeof y, file) != sizeof y)
break;
while (y.d_ino != x.st_ino);
}
else do {
if (fread((char *)&y, 1, sizeof y, file) != sizeof y)
break;
stat(y.d_name, &xx);
} while (xx.st_ino != x.st_ino || xx.st_dev != x.st_dev);
fclose(file);
if (cat(name))
break;
}
i = strlen(name);
name[i+1] = 0;
while (--i >= 0) name[i+1] = name[i];
name[0] = '/';
}
#endif
cat(name)
register char *name; { /* return 1 to exit */
register int i,j;
i = -1;
while(y.d_name[++i] != 0);
if((off+i+2) > 511)return(1);
for(j = off +1; j >= 0; --j)name[j+i+1] = name[j];
off = i + off + 1;
name[i] = '/';
for(--i; i>= 0; --i)name[i] = y.d_name[i];
return(0);
}
/*
this function takes a file name and tells whether it is a
directory or on. Returns 1 if so, 0 otherwise.
null strings etc. return 0.
*/
isdirectory(fn)
char *fn;
{
int i,ret=0;
if(fn == NULL || *fn == 0)return(0);
i = strlen(fn);
if(i == 1){
if(strcmp(fn,".") == 0)ret = 1;
if(strcmp(fn,"/") == 0)ret = 1;
}
else if(i == 2){
if(strcmp(fn,"..") == 0)ret = 1;
if(strcmp(fn,"/.") == 0)ret = 1;
}
else {
if(strcmp(fn+i-2,"/.") == 0)ret = 1;
if(strcmp(fn+i-3,"/..") == 0)ret = 1;
}
return(ret);
}