Commit | Line | Data |
---|---|---|
23f1e696 | 1 | static char sccsid[] = "@(#)net.c 4.2 (Berkeley) %G%"; |
b2c722c8 KM |
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; | |
b2c722c8 KM |
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 | |
23f1e696 KM |
421 | static FILE *file; |
422 | ||
b2c722c8 KM |
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 | |
23f1e696 | 463 | static DIR *file; |
b2c722c8 KM |
464 | static struct stat xx; |
465 | ||
466 | gwd(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 | ||
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 | } | |
23f1e696 KM |
548 | |
549 | blkcpy(from, to, size) | |
550 | register *from, *to; | |
551 | register int size; | |
552 | { | |
553 | while (size-- > 0) | |
554 | *to++ = *from++; | |
555 | } |