xref: /original-bsd/old/berknet/net.c (revision 62734ea8)
1 static char sccsid[] = "@(#)net.c	4.2	(Berkeley)	09/12/82";
2 
3 /* sccs id variable */
4 static char *net_sid = "@(#)net.c	1.8";
5 
6 # include "defs.h"
7 /* must be setuid root */
8 /*
9 	net - -b -c cmd -f -i file -l name -mmach -n -o file -p passwd
10 		-r file -s file -u uid -w -x -y -z command
11 
12 	-	take from standard input
13 	-b	never send anything back
14 	-c cmd	think of this as a "cmd" *
15 	-f	force prompting of user name and password
16 	-i file	remote stdin *
17 	-l name remote login name
18 	-m Mach	remote machine
19 	-n	do not write back anything, always mail them back
20 	-o file	remote stdout & stderr *
21 	-p pass remote password
22 	-q 	quiet option, send back only if rcode !=0 or if there is stdout
23 	-r file	local response file
24 	-s file	local stdin file *
25 
26 	(super users only, always skip login/passwd check:)
27 	-u uid	net queue files should be owned by uid (16 bits)
28 	-w	this is a write/mail response cmd *
29 	-x	this is being forwarded through us to another machine *
30 	-y	skip login/password check *
31 	-z	this is a response file being returned *
32 
33 	* = not documented in net(NEW)
34 
35 */
36 /*
37 	code	option	reason
38 	q		normal request
39 	w	-w	message to be written back
40 	 	-x	being forwarded through us
41 	y	-y	simply skips login check (used by netlpr)
42 	s	-z	normal response
43 */
44 /* global variables */
45 struct userinfo status;
46 
47 /* local variables */
48 static char dfname[]=		DFNAME;
49 
50 main(argc, argv)
51   char **argv; {
52 	register int i;
53 	int outerror(),uid;
54 	char localin[FNS], skey[30];
55 	char buf[BUFSIZ], suid[10];
56 	char sin =0, zopt = 0, wopt = 0, yopt = 0, xopt = 0;
57 	char *s,**sargv;
58 	long cnt = 0L, maxfile = MAXFILELARGE;
59 	FILE *file, *temp, *rfile;
60 	struct utmp *putmp;
61 	struct stat statbuf;
62 	struct header hd;
63 
64 	debugflg = DBV;
65 	hd.hd_scmdact[0] = hd.hd_srespfile[0] = hd.hd_soutfile[0] = 0;
66 	hd.hd_sinfile[0] = hd.hd_scmdvirt[0] = hd.hd_sttyname[0] = 0;
67 	localin[0] = 0;
68 	suid[0] = 0;
69 	sargv = argv;
70 
71 	if(isatty(0)) strcat(hd.hd_sttyname,ttyname(0));
72 	else if(isatty(2)) strcat(hd.hd_sttyname,ttyname(2));
73 	remote = 0;
74 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
75 		signal(SIGHUP, outerror);
76 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
77 		signal(SIGQUIT, outerror);
78 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
79 		signal(SIGINT, outerror);
80 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
81 		signal(SIGTERM, outerror);
82 
83 	while(argc > 1 && argv[1][0] == '-'){
84 		argc--; argv++;
85 		switch(argv[0][1]){
86 		case 0:
87 			sin++;
88 			break;
89 		case 'b':
90 			status.nonotify++;
91 			break;
92 		case 'c':
93 			harg(hd.hd_scmdvirt);
94 			break;
95 		case 'f':
96 			status.force++;
97 			break;
98 		case 'i':
99 			harg(hd.hd_sinfile);
100 			break;
101 		case 'l':
102 			harg(status.login);
103 			break;
104 		case 'm':
105 			harg(buf);
106 			remote = lookup(buf);
107 			if(remote == 0){
108 				fprintf(stderr,"Unknown machine %s\n",buf);
109 				exit(EX_NOHOST);
110 			}
111 			break;
112 		case 'n':
113 			status.nowrite++;
114 			break;
115 		case 'o':
116 			harg(hd.hd_soutfile);
117 			break;
118 		case 'p':
119 			harg(status.mpasswd);
120 			if(status.mpasswd[0] == 0)
121 			  	strcpy(status.mpasswd,"\n\n");
122 			break;
123 		case 'q':
124 			status.quiet++;
125 			break;
126 		case 'r':
127 			harg(buf);
128 			addir(hd.hd_srespfile,buf);
129 			break;
130 		case 's':
131 			harg(localin);
132 			break;
133 		case 'u':
134 			harg(suid);
135 			break;
136 		case 'w':
137 			wopt++;
138 			break;
139 		case 'x':
140 			xopt++;
141 			break;
142 		case 'y':
143 			yopt++;
144 			break;
145 		case 'z':
146 			zopt++;
147 			break;
148 		default:
149 			fprintf(stderr,"Unknown option %s\n",argv[0]);
150 			break;
151 		}
152 		}
153 	while(argc > 1){
154 		argc--; argv++;
155 		strcat(hd.hd_scmdact,argv[0]);
156 		strcat(hd.hd_scmdact," ");
157 		}
158 	sargv[1] = 0;		/* so ps won't show passwd ??? */
159 	hd.hd_uidfrom = uid = getuid();
160 	hd.hd_gidfrom = getgid();
161 	hd.hd_code = 'q';
162 	if(zopt || wopt || yopt || xopt || suid[0] != 0){
163 		/* check z or w or y or x option permission */
164 # ifndef TESTING
165 		/* check effective user id ?? */
166 		if (uid != SUPERUSER && uid != NUID) {
167 			fprintf(stderr, "Error: Not super-user\n");
168 			fprintf(stderr,"zopt %d wopt %d yopt %d xopt %d suid[0] %s\n", zopt, wopt, yopt, xopt, suid);
169 			fprintf(stderr,"uid %d\n", uid);
170 			debugflg = 1;
171 			printhd(&hd);
172 			outerror(EX_UNAVAILABLE);
173 			}
174 # endif
175 		hd.hd_code = zopt? 's': 'w';
176 		hd.hd_code = yopt? 'y': hd.hd_code;
177 		if (status.mpasswd[0] == 0)	/* no passwd required */
178 			strcpy(status.mpasswd, "\n");
179 		debug("zopt %d wopt %d yopt %d xopt %d suid[0] %s\n", zopt, wopt, yopt, xopt, suid);
180 		debug("uid %d\n", uid);
181 		if(xopt)
182 			setuid(SUPERUSER);
183 	}
184 #ifdef CRN
185 	strcpy( status.jobno, MAGICCRN );	/* default (invalid) crn */
186 #else
187 	strcpy( status.jobno, "XYZZ");		/* default (invalid) crn */
188 #endif
189 
190 	if(hd.hd_code == 'q' && !xopt){
191 		/* read passwd file, get status.localname & crn */
192 		passwdent();
193 	}
194 
195 	/* sets remote,status.login,status.force,status.mpasswd,
196 		status.nonotify, status.nowrite */
197 	/* may read passwd file if getenv(HOME) reads it */
198 	commandfile();
199 	if(status.force)status.login[0] = status.mpasswd[0] = 0;
200 
201 	/* look up login name and passwd in the environment */
202 	envloginpasswd(remote,status.login,status.mpasswd);
203 
204 
205 	if(remote == 0)remote = getremote(local);
206 # ifndef TESTING
207 	if(remote == local){
208 		fprintf(stderr,"Request sent to local machine - doesn't make sense\n");
209 		/* outerror(); */
210 		}
211 # endif
212 	strcat(status.defcmd," ");
213 	if(strlen(hd.hd_scmdact) == 0)strcpy(hd.hd_scmdact,status.defcmd);
214 	hd.hd_scmdact[strlen(hd.hd_scmdact)-1] = 0;
215 	do {
216 		mktemp(dfname); /* make until unique!! */
217 	} while(stat(dfname,&statbuf) >= 0);
218 	/* determine through machine */
219 	i = gothru(local,remote);
220 	if(i == 0){
221 		s = longname(remote);
222 		if(s != 0)fprintf(stderr,"No path to %s machine.\n",s);
223 		else fprintf(stderr,"Unknown machine\n");
224 		outerror(EX_NOHOST);
225 		}
226 	dfname[strlen(dfname)-11] = i;		/* set directory */
227 	dfname[strlen(dfname)-7] = i;		/* set file (unused) */
228 	/* check to see if data files are directories */
229 	if(isdirectory(hd.hd_srespfile) || isdirectory(hd.hd_sinfile) || isdirectory(hd.hd_soutfile)){
230 		fprintf(stderr,"%s is a directory, must be a file\n",
231 			isdirectory(hd.hd_srespfile)    ? hd.hd_srespfile :
232 			isdirectory(hd.hd_sinfile)  ? hd.hd_sinfile :
233 			hd.hd_soutfile);
234 		outerror(EX_USAGE);
235 	}
236 	if(suid[0] != 0)uid = atoi(suid);
237 	if(hd.hd_srespfile[0]){
238 		if(strcmp(hd.hd_srespfile,"/dev/tty") == 0){
239 		fprintf(stderr,"Can't have /dev/tty as response file.\n");
240 			outerror(EX_USAGE);
241 			}
242 		if(stat(hd.hd_srespfile,&statbuf) == -1){
243 			strcpy(buf,hd.hd_srespfile);
244 			s = &buf[0];
245 			s = s + strlen(buf) - 1;
246 			while(*s != '/' && s > &(buf[0]))s--;
247 			*s = 0;
248 			debug("chkdir %s",buf);
249 			if(strlen(buf) == 0)strcpy(buf,".");
250 			if(access(buf,2) == -1){
251 				perror(buf);
252 				outerror(EX_USAGE);
253 				}
254 			if((rfile=fopen(hd.hd_srespfile,"w")) == NULL){
255 				perror(hd.hd_srespfile);
256 				outerror(EX_USAGE);
257 				}
258 			chmod(hd.hd_srespfile,0600);
259 			fclose(rfile);
260 			mchown(hd.hd_srespfile,uid,hd.hd_gidfrom);
261 			}
262 		else if(access(hd.hd_srespfile,2) == -1){
263 			perror(hd.hd_srespfile);
264 			outerror(EX_USAGE);
265 			}
266 		else if(getsize(&statbuf) != 0L){
267 			fprintf(stderr,"%s must have 0-length or not exist\n",
268 				hd.hd_srespfile);
269 			outerror(EX_USAGE);
270 		}
271 	}
272 	/* go ahead and prompt for login name and passwd, if neccessary,
273 	   as long as the X option has not been specified */
274 	if(hd.hd_code == 'q' && !xopt)promptlogin(remote);
275 
276 	/* at this point, we create the dfa... file */
277 	file = fopen(dfname,"w");
278 	if(file == NULL){
279 		perror(dfname);
280 		outerror(EX_OSERR);
281 		}
282 	chmod(dfname,0600);
283 	mchown(dfname,uid,getgid());
284 	if(xopt)goto stickit;
285 	if(status.mpasswd[0] == '\n')
286 		status.mpasswd[0] = 0;
287 	if(status.mpasswd[0] == 0 && hd.hd_code == 'q' &&
288 		strcmp(status.login,"network") != 0){
289 		fprintf(stderr,"Zero-length password not allowed\n");
290 		outerror(EX_USAGE);
291 		}
292 	if(hd.hd_code == 'q' && (streql(status.login,"root") == 0 ||
293 		streql(status.login,"ruut") == 0)){
294 		fprintf(stderr,"Can't login as root through the network\n");
295 		outerror(EX_USAGE);
296 		}
297 	makeuukey(skey,status.login,remote);
298 	nbsencrypt(status.mpasswd,skey,hd.hd_sencpasswd);
299 	enmask(status.mpasswd);
300 	hd.hd_lttytime = 0;
301 	if(hd.hd_sttyname[0] && status.nowrite == 0){
302 		putmp = getutmp(hd.hd_sttyname);
303 		if(putmp != NULL) hd.hd_lttytime = putmp->ut_time;
304 	}
305 /*
306 	debug("p:%s:\n",status.mpasswd);
307 */
308 	/* write the header info onto 'file' */
309 	hd.hd_mchto = remote;
310 	hd.hd_mesgid.msg_mch = hd.hd_mchfrom = local;
311 	hd.hd_vmajor = VMAJOR;
312 	hd.hd_vminor = VMINOR;
313 	strcpy(hd.hd_snto,status.login);
314 	strcpy(hd.hd_snfrom,status.localname);
315 	strcpy(hd.hd_spasswd,status.mpasswd);
316 	strcpy(hd.hd_ijobno, status.jobno );
317 	hd.hd_mesgid.msg_ltime = hd.hd_ltimesent = gettime();
318 	hd.hd_fquiet = status.quiet;
319 	hd.hd_fnonotify = status.nonotify;
320 	hd.hd_mesgid.msg_pid = getpid();
321 	hd.hd_fcompressed = 0;
322 	/* handle account pairs, accounts which do not require
323 	   a passwd if you are logged in on the same one here */
324 	hd.hd_facctpair = fisacctpair(&hd);
325 
326 	writehdfd(&hd,file);
327 	printhd(&hd);
328 stickit:
329 	if(sin)
330 		while((i = fread(buf,1,BUFSIZ,stdin)) > 0){
331 			if(fwrite(buf,1,i,file) != i){
332 				perror("net queue file");
333 				outerror(EX_OSFILE);
334 				}
335 			if((cnt += i) > maxfile)goto toobig;
336 			if(feof(stdin))break;
337 			}
338 	else if(localin[0]){
339 		if(access(localin,4) == -1){
340 			perror(localin);
341 			outerror(EX_OSFILE);
342 			}
343 		temp = fopen(localin,"r");
344 		if(temp == NULL){
345 			perror(localin);
346 			outerror(EX_OSFILE);
347 			}
348 		while((i = fread(buf,1,BUFSIZ,temp)) > 0){
349 			if((cnt += i) > maxfile)goto toobig;
350 			if(fwrite(buf,1,i,file) != i){
351 				perror("net queue file");
352 				outerror(EX_OSFILE);
353 				}
354 			}
355 		fclose(temp);
356 		}
357 	fclose(file);
358 	chmod(dfname,0400);
359 	dfname[strlen(dfname)-9] = 'c';
360 	file = fopen(dfname,"w");
361 	chmod(dfname,0400);
362 	fclose(file);
363 	mchown(dfname,uid,getgid());
364 	exit(EX_OK);
365 toobig:
366 	fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile);
367 	outerror(EX_USAGE);		/* no return */
368 	}
369 /*
370    called if there is an error, makes sure that the files created
371    are deleted and the terminal is reset to echo
372 */
373 outerror(ret){
374 	register int i;
375 	struct sgttyb stt;
376 	signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN);
377 	signal(SIGQUIT,SIG_IGN); signal(SIGTERM,SIG_IGN);
378 	unlink(dfname);
379 	i = strlen(dfname) - 9;
380 	dfname[i] = (dfname[i] == 'c' ? 'd' : 'c');
381 	unlink(dfname);
382 	if(gtty(0,&stt) >= 0){
383 		stt.sg_flags |= ECHO;
384 		stty(0,&stt);
385 		}
386 	exit(ret);
387 	}
388 enmask(s)
389   register char *s; {
390 	while(*s){
391 		*s &= 0177;		/* strip quote bites */
392 		*s++ ^= 040;		/* invert upper-lower */
393 		}
394 	}
395 addir(s,t)
396   register char *s, *t; {
397 	if(t[0] == '/')strcpy(s,t);
398 	else {
399 		gwd(s);
400 		strcat(s,t);
401 		}
402 	}
403 
404 /* returns true if phd is an account pair, false otherwise */
405 fisacctpair(phd)
406 register struct header *phd;
407 {
408 	return(0);
409 }
410 
411 
412 
413 static struct stat x;
414 static struct direct y;
415 static int off = -1;
416 
417 
418 /* these three routines gwd, cat, ckroot and
419    data structures x, y, off, do a pwd to string name */
420 #ifdef V6
421 static FILE *file;
422 
423 gwd(name)
424   register char *name; {
425 	*name = 0;
426 	for(;;){
427 		stat(".",&x);
428 		if((file = fopen("..","r")) == NULL)break;
429 		do {
430 			if(fread(&y,1,sizeof y,file) != sizeof y)break;
431 			} while(y.d_ino != x.st_ino);
432 		fclose(file);
433 		if(y.d_ino == ROOTINO){
434 			ckroot(name);
435 			break;
436 			}
437 		if(cat(name))break;
438 		chdir("..");
439 		}
440 	chdir(name);
441 	}
442 ckroot(name)
443   char *name; {
444 	register int i;
445 	if(stat(y.d_name,&x) < 0)return;
446 	i = x.st_dev;
447 	if(chdir("/") < 0)return;
448 	if((file = fopen("/","r")) == NULL)return;
449 	do {
450 		if(fread(&y,1,sizeof y,file) != sizeof y)return;
451 		if(y.d_ino == 0)continue;
452 		if(stat(y.d_name,&x) < 0)return;
453 		} while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR);
454 	if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0)
455 		if(cat(name))return;
456 	i = strlen(name);
457 	name[i+1] = 0;
458 	while(--i >= 0)name[i + 1] = name[i];
459 	name[0] = '/';
460 	return;
461 	}
462 #else
463 static DIR *file;
464 static struct stat xx;
465 
466 gwd(name)
467   register char *name;  {
468 	int rdev, rino;
469 	register int i;
470 	register struct direct *dp;
471 
472 	*name = 0;
473 	stat("/", &x);
474 	rdev = x.st_dev;
475 	rino = x.st_ino;
476 	for (;;) {
477 		stat(".", &x);
478 		if (x.st_ino == rino && x.st_dev == rdev)
479 			break;
480 		if ((file = opendir("..")) == NULL)
481 			break;
482 		fstat(file->dd_fd, &xx);
483 		chdir("..");
484 		if (x.st_dev == xx.st_dev) {
485 			if (x.st_ino == xx.st_ino)
486 				break;
487 			do
488 				if ((dp = readdir(file)) == NULL)
489 					break;
490 			while (dp->d_ino != x.st_ino);
491 		}
492 		else do {
493 			if ((dp = readdir(file)) == NULL)
494 				break;
495 			stat(dp->d_name, &xx);
496 		} while (xx.st_ino != x.st_ino || xx.st_dev != x.st_dev);
497 		blkcpy(dp, &y, DIRSIZ(dp));
498 		closedir(file);
499 		if (cat(name))
500 			break;
501 	}
502 	i = strlen(name);
503 	name[i+1] = 0;
504 	while (--i >= 0) name[i+1] = name[i];
505 	name[0] = '/';
506 }
507 #endif
508 
509 cat(name)
510   register char *name; {		/* return 1 to exit */
511 	register int i,j;
512 	i = -1;
513 	while(y.d_name[++i] != 0);
514 	if((off+i+2) > 511)return(1);
515 	for(j = off +1; j >= 0; --j)name[j+i+1] = name[j];
516 	off = i + off + 1;
517 	name[i] = '/';
518 	for(--i; i>= 0; --i)name[i] = y.d_name[i];
519 	return(0);
520 	}
521 
522 
523 /*
524 	this function takes a file name and tells whether it is a
525 	directory or on. Returns 1 if so, 0 otherwise.
526 	null strings etc. return 0.
527 */
528 isdirectory(fn)
529 	char *fn;
530 {
531 	int i,ret=0;
532 	if(fn == NULL || *fn == 0)return(0);
533 	i = strlen(fn);
534 	if(i == 1){
535 		if(strcmp(fn,".")       == 0)ret = 1;
536 		if(strcmp(fn,"/")       == 0)ret = 1;
537 	}
538 	else if(i == 2){
539 		if(strcmp(fn,"..")      == 0)ret = 1;
540 		if(strcmp(fn,"/.")      == 0)ret = 1;
541 	}
542 	else {
543 		if(strcmp(fn+i-2,"/.")  == 0)ret = 1;
544 		if(strcmp(fn+i-3,"/..") == 0)ret = 1;
545 	}
546 	return(ret);
547 }
548 
549 blkcpy(from, to, size)
550 	register *from, *to;
551 	register int size;
552 {
553 	while (size-- > 0)
554 		*to++ = *from++;
555 }
556