BSD 4_1c_2 release
[unix-history] / usr / src / ucb / berknet / net.c
CommitLineData
e804469b 1static char sccsid[] = "@(#)net.c 4.2 (Berkeley) 9/12/82";
b2c722c8
KM
2
3/* sccs id variable */
4static 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 */
45struct userinfo status;
46
47/* local variables */
48static char dfname[]= DFNAME;
49
50main(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);
328stickit:
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);
365toobig:
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*/
373outerror(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 }
388enmask(s)
389 register char *s; {
390 while(*s){
391 *s &= 0177; /* strip quote bites */
392 *s++ ^= 040; /* invert upper-lower */
393 }
394 }
395addir(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 */
405fisacctpair(phd)
406register struct header *phd;
407{
408 return(0);
409}
410
411
412
413static struct stat x;
414static struct direct y;
b2c722c8
KM
415static 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
23f1e696
KM
421static FILE *file;
422
b2c722c8
KM
423gwd(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 }
442ckroot(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
23f1e696 463static DIR *file;
b2c722c8
KM
464static struct stat xx;
465
466gwd(name)
467 register char *name; {
468 int rdev, rino;
469 register int i;
23f1e696 470 register struct direct *dp;
b2c722c8
KM
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;
23f1e696 480 if ((file = opendir("..")) == NULL)
b2c722c8 481 break;
23f1e696 482 fstat(file->dd_fd, &xx);
b2c722c8
KM
483 chdir("..");
484 if (x.st_dev == xx.st_dev) {
485 if (x.st_ino == xx.st_ino)
486 break;
487 do
23f1e696 488 if ((dp = readdir(file)) == NULL)
b2c722c8 489 break;
23f1e696 490 while (dp->d_ino != x.st_ino);
b2c722c8
KM
491 }
492 else do {
23f1e696 493 if ((dp = readdir(file)) == NULL)
b2c722c8 494 break;
23f1e696 495 stat(dp->d_name, &xx);
b2c722c8 496 } while (xx.st_ino != x.st_ino || xx.st_dev != x.st_dev);
23f1e696
KM
497 blkcpy(dp, &y, DIRSIZ(dp));
498 closedir(file);
b2c722c8
KM
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
509cat(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*/
528isdirectory(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}
23f1e696
KM
548
549blkcpy(from, to, size)
550 register *from, *to;
551 register int size;
552{
553 while (size-- > 0)
554 *to++ = *from++;
555}