|
|
1.1 root 1: # include "defs.h"
2: /* must be setuid root */
3: /*
4: net - -b -c cmd -f -i file -l name -mmach -n -o file -p passwd
5: -r file -s file -u uid -w -x -y -z command
6:
7: - take from standard input
8: -b never send anything back
9: -c cmd think of this as a "cmd" *
10: -f force prompting of user name and password
11: -i file remote stdin *
12: -l name remote login name
13: -m Mach remote machine
14: -n do not write back anything, always mail them back
15: -o file remote stdout & stderr *
16: -p pass remote password
17: -q quiet option, send back only if rcode !=0 or if there is stdout
18: -r file local response file
19: -s file local stdin file *
20:
21: (super users only, always skip login/passwd check:)
22: -u uid net queue files should be owned by uid (16 bits)
23: -w this is a write/mail response cmd *
24: -x this is being forwarded through us to another machine *
25: -y skip login/password check *
26: -z this is a response file being returned *
27:
28: * = not documented in net(NEW)
29:
30: */
31: /*
32: code option reason
33: q normal request
34: w -w message to be written back
35: -x being forwarded through us
36: y -y simply skips login check (used by netlpr)
37: s -z normal response
38: */
39: static char dfname[]= DFNAME;
40:
41: main(argc, argv)
42: char **argv; {
43: register int i;
44: int outerror(),uid;
45: char *genparmlist();
46: char resp[FNS], infile[FNS], outfile[FNS], localin[FNS];
47: char buf[BUFSIZ], suid[10];
48: char sin =0, code, zopt = 0, wopt = 0, yopt = 0, xopt = 0;
49: char *s,*sn;
50: char sTtyname[20], sCmdAct[BUFSIZ], sCmdVirt[BUFSIZ];
51: long cnt = 0L, maxfile = MAXFILE, lTtytime;
52: char cflag = 'a';
53: FILE *file, *temp, *rfile;
54: struct utmp utmpstr;
55: struct stat statbuf;
56:
57: debugflg = DBV;
58: argv[argc] = 0;
59: sCmdAct[0] = resp[0] = outfile[0] = infile[0] = 0;
60: sCmdVirt[0] = localin[0] = 0;
61: sTtyname[0] = 0;
62: suid[0] = 0;
63:
64: if(isatty(0)) strcat(sTtyname,ttyname(0));
65: else if(isatty(2)) strcat(sTtyname,ttyname(2));
66: remote = 0;
67: signal(SIGHUP,outerror);
68: signal(SIGQUIT,outerror);
69: signal(SIGINT,outerror);
70: signal(SIGTRM,outerror);
71:
72: while(argc > 1 && argv[1][0] == '-'){
73: argc--; argv++;
74: switch(argv[0][1]){
75: case 0: sin++; break;
76: case 'b': status.nonotify++; break;
77: case 'c': harg(sCmdVirt,&argc,&argv); break;
78: case 'f': status.force++; break;
79: case 'i': harg(infile,&argc,&argv); break;
80: case 'l': harg(status.login,&argc,&argv); break;
81: case 'm': harg(buf,&argc,&argv); remote = lookup(buf); break;
82: case 'n': status.nowrite++; break;
83: case 'o': harg(outfile,&argc,&argv); break;
84: case 'p':
85: harg(status.mpasswd,&argc,&argv);
86: if(status.mpasswd[0] == 0)
87: strcpy(status.mpasswd,"\n\n");
88: break;
89: case 'q': status.quiet++; break;
90: case 'r': harg(buf,&argc,&argv); addir(resp,buf); break;
91: case 's': harg(localin,&argc,&argv); break;
92: case 'u': harg(suid,&argc,&argv); break;
93: case 'w': wopt++; break;
94: case 'x': xopt++; break;
95: case 'y': yopt++; break;
96: case 'z': zopt++; break;
97: default:
98: fprintf(stderr,"Unknown option %s\n",argv[0]);
99: break;
100: }
101: }
102: while(argc > 1){
103: argc--; argv++;
104: strcat(sCmdAct,argv[0]);
105: strcat(sCmdAct," ");
106: }
107: uid = getuid();
108: code = 'q';
109: if(zopt || wopt || yopt || xopt || suid[0] != 0){
110: /* check z or w or y or x option permission */
111: # ifndef TESTING
112: if(uid != SUPERUSER){
113: fprintf(stderr,"Error: Not super-user");
114: outerror();
115: }
116: # endif
117: code = zopt ? 's' : 'w';
118: code = yopt ? 'y' : code;
119: if(status.mpasswd[0] == 0) /* no passwd required */
120: strcpy(status.mpasswd,"\n");
121: }
122:
123: status.jobno = 32767; /* default (invalid) job number */
124: if(code == 'q' && !xopt){
125: if((sn = SnCurrent()) == NULL
126: /* || machtype[local-'a'] == M_CC */)
127: /* turns out we never use jobno, except in netlpr */
128: /* read passwd file, get status.localname & jobno */
129: passwdent();
130: else
131: /* don't bother reading passwd file, don't need jobno */
132: strcpy(status.localname,sn);
133: }
134:
135: /* sets remote,status.login,status.force,status.mpasswd,
136: status.nonotify, status.nowrite */
137: /* may read passwd file if getenv(HOME) reads it */
138: commandfile();
139:
140: if(remote == 0)remote = getremote(local);
141: # ifndef TESTING
142: if(remote == local){
143: fprintf(stderr,"Request sent to local machine - doesn't make sense\n");
144: /* outerror(); */
145: }
146: # endif
147: strcat(status.defcmd," ");
148: if(strlen(sCmdAct) == 0)strcpy(sCmdAct,status.defcmd);
149: sCmdAct[strlen(sCmdAct)-1] = 0;
150: mktemp(dfname);
151: /* determine through machine */
152: i = gothru(local,remote);
153: if(i == 0){
154: s = longname(remote);
155: if(s != 0)fprintf(stderr,"No path to %s machine.\n",s);
156: else fprintf(stderr,"Unknown machine\n");
157: outerror();
158: }
159: dfname[strlen(dfname)-11] = i; /* set directory */
160: dfname[strlen(dfname)-7] = i; /* set file (unused) */
161: /* check to see if data files are directories */
162: if(isdirectory(resp) || isdirectory(infile) || isdirectory(outfile)){
163: fprintf(stderr,"%s is a directory, must be a file\n",
164: isdirectory(resp) ? resp :
165: isdirectory(infile) ? infile :
166: outfile);
167: outerror();
168: }
169: if(suid[0] != 0)uid = atoi(suid);
170: if(resp[0]){
171: if(strcmp(resp,"/dev/tty") == 0){
172: fprintf(stderr,"Can't have /dev/tty as response file.\n");
173: outerror();
174: }
175: if(stat(resp,&statbuf) == -1){
176: strcpy(buf,resp);
177: s = &buf[0];
178: s = s + strlen(buf) - 1;
179: while(*s != '/' && s > &(buf[0]))s--;
180: *s = 0;
181: debug("chkdir %s",buf);
182: if(strlen(buf) == 0)strcpy(buf,".");
183: if(access(buf,2) == -1){
184: perror(buf);
185: outerror();
186: }
187: if((rfile=fopen(resp,"w")) == NULL){
188: perror(resp);
189: outerror();
190: }
191: chmod(resp,0600);
192: fclose(rfile);
193: mchown(resp,uid,getgid());
194: }
195: else if(access(resp,2) == -1){
196: perror(resp);
197: outerror();
198: }
199: }
200: /* go ahead and prompt for login name and passwd, if neccessary,
201: as long as the X option has not been specified */
202: if(code == 'q' && !xopt)promptlogin(remote);
203:
204: /* at this point, we create the dfa... file */
205: file = fopen(dfname,"w");
206: if(file == NULL){
207: perror(dfname);
208: outerror();
209: }
210: chmod(dfname,0600);
211: mchown(dfname,uid,getgid());
212: if(xopt)goto stickit;
213: if(status.mpasswd[0] == '\n')
214: status.mpasswd[0] = 0;
215: # ifndef NEWPROT
216: if(machtype[local-'a'] == M_CC && machtype[remote-'a'] == M_CC
217: && status.mpasswd[0] != 0){
218: s = crypt(status.mpasswd);
219: strcpy(status.mpasswd,s);
220: }
221: # endif
222: if(status.mpasswd[0] == 0 && code == 'q' &&
223: strcmp(status.login,"network") != 0){
224: fprintf(stderr,"Zero-length password not allowed\n");
225: outerror();
226: }
227: if(code == 'q' && (streql(status.login,"root") == 0 ||
228: streql(status.login,"ruut") == 0)){
229: fprintf(stderr,"Can't login as root through the network\n");
230: outerror();
231: }
232: # ifdef SPACCT
233: /* handle special accounts */
234: /* give a value for mgid and muid */
235: strcpy(status.mpasswd,handlesp(status.login,status.mpasswd,
236: status.localname,status.muid,status.mgid));
237: # endif
238: enmask(status.mpasswd);
239: lTtytime = 0;
240: if(sTtyname[0] && status.nowrite == 0){
241: temp = fopen("/etc/utmp","r");
242: if(temp == NULL){
243: perror("/etc/utmp");
244: outerror();
245: }
246: while(fread(&utmpstr,1,sizeof utmpstr,temp) == sizeof utmpstr)
247: # ifdef OLDTTY
248: if(utmpstr.ut_tty == sTtyname[8]){
249: # else
250: if(strcmp(utmpstr.ut_line,sTtyname+5) == 0){
251: # endif
252: lTtytime = utmpstr.ut_time;
253: break;
254: }
255: }
256: /*
257: debug("p:%s:\n",status.mpasswd);
258: */
259: /* cflag is initially 'a'. Add the flags as needed. */
260: if(status.nonotify)cflag += F_NONOTIFY;
261: if(status.quiet)cflag += F_QUIET;
262: /*
263: protocol:
264: code, remote mach, local mach, version stamp (2), remote login name,
265: password, -i, -o, -r files,
266: local login name, terminal, flag, utmp tty login time,
267: cc jobno(variable parameter list), current time,
268: command '\n' real command '\n'
269: any data
270:
271: changes:
272: 1) remove header
273: 3) use ascii length instead of 4 bytes
274: 4) encrypt the login name, command, and part of data as well
275: */
276:
277: fprintf(file,
278: "%c :%c :%c :%c :%c :%s :%s :%s :%s :%s :%s :%s :%c :%lo :%d%s :%ld :",
279: code,remote,local,VMAJOR+'a',VMINOR+'a',status.login,
280: status.mpasswd,infile,outfile,resp,
281: status.localname,sTtyname,cflag,lTtytime,
282: status.jobno,genparmlist(),gettime()-TIMEBASE);
283: fputs(sCmdAct,file);
284: putc('\n',file);
285: fputs(sCmdVirt,file);
286: putc('\n',file);
287: stickit:
288: /* between ingres machines, allow long files */
289: /* this should be parametrized on a per machine pair basis */
290: if(machtype[local - 'a'] == M_INGRES &&
291: machtype[remote - 'a'] == M_INGRES)
292: maxfile = MAXFILELARGE;
293: if(sin)
294: while((i = fread(buf,1,BUFSIZ,stdin)) > 0){
295: if(fwrite(buf,1,i,file) != i){
296: perror("net queue file");
297: outerror();
298: }
299: if((cnt += i) > maxfile)goto toobig;
300: if(feof(stdin))break;
301: }
302: else if(localin[0]){
303: if(access(localin,4) == -1){
304: perror(localin);
305: outerror();
306: }
307: temp = fopen(localin,"r");
308: if(temp == NULL){
309: perror(localin);
310: outerror();
311: }
312: while((i = fread(buf,1,BUFSIZ,temp)) > 0){
313: if((cnt += i) > maxfile)goto toobig;
314: if(fwrite(buf,1,i,file) != i){
315: perror("net queue file");
316: outerror();
317: }
318: }
319: fclose(temp);
320: }
321: fclose(file);
322: chmod(dfname,0400);
323: dfname[strlen(dfname)-9] = 'c';
324: file = fopen(dfname,"w");
325: chmod(dfname,0400);
326: fclose(file);
327: mchown(dfname,uid,getgid());
328: exit(0);
329: toobig:
330: fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile);
331: outerror(); /* no return */
332: }
333: /*
334: called if there is an error, makes sure that the files created
335: are deleted and the terminal is reset to echo
336: */
337: outerror(){
338: register int i;
339: struct sgttyb stt;
340: signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN);
341: signal(SIGQUIT,SIG_IGN); signal(SIGTRM,SIG_IGN);
342: unlink(dfname);
343: i = strlen(dfname) - 9;
344: dfname[i] = (dfname[i] == 'c' ? 'd' : 'c');
345: unlink(dfname);
346: if(gtty(0,&stt) >= 0){
347: stt.sg_flags |= ECHO;
348: stty(0,&stt);
349: }
350: exit(1);
351: }
352: enmask(s)
353: register char *s; {
354: # ifdef NEWPROT
355: static char buf[20];
356: strcpy(s,nbsencrypt(s,THEKEY,buf));
357: # else
358: while(*s){
359: *s &= 0177; /* strip quote bites */
360: *s++ ^= 040; /* invert upper-lower */
361: }
362: # endif
363: }
364: addir(s,t)
365: register char *s, *t; {
366: if(t[0] == '/')strcpy(s,t);
367: else {
368: gwd(s);
369: strcat(s,t);
370: }
371: }
372: /* returns pass if not special, otherwise returns funny passwd */
373: /* list of special accounts must be consistent - with netdaemon.c */
374: char *handlesp(log,pass,localname,luid,lgid)
375: char *log,*pass,*localname;{
376: /* experimental */
377: # ifdef SPACCT
378: long lt;
379: char str[20];
380: if(strcmp(log,localname) == 0 && luid != 0 && lgid == 0 && (
381: strcmp(log,"source") == 0
382: || strcmp(log,"daemon") == 0
383: )) {
384: lt = lgid;
385: lt = (lt << 16) | luid;
386: sprintf(str,"%ld",lt);
387: return(str);
388: }
389: # endif
390: return(pass);
391: }
392:
393:
394:
395: static struct stat x;
396: static struct direct y;
397: static FILE *file;
398: static int off = -1;
399:
400:
401: /* these three routines gwd, cat, ckroot and
402: data structures x, y, off, do a pwd to string name */
403: gwd(name)
404: register char *name; {
405: *name = 0;
406: for(;;){
407: stat(".",&x);
408: if((file = fopen("..","r")) == NULL)break;
409: do {
410: if(fread(&y,1,sizeof y,file) != sizeof y)break;
411: } while(y.d_ino != x.st_ino);
412: fclose(file);
413: if(y.d_ino == ROOTINO){
414: ckroot(name);
415: break;
416: }
417: if(cat(name))break;
418: chdir("..");
419: }
420: chdir(name);
421: }
422:
423: cat(name)
424: register char *name; { /* return 1 to exit */
425: register int i,j;
426: i = -1;
427: while(y.d_name[++i] != 0);
428: if((off+i+2) > 511)return(1);
429: for(j = off +1; j >= 0; --j)name[j+i+1] = name[j];
430: off = i + off + 1;
431: name[i] = '/';
432: for(--i; i>= 0; --i)name[i] = y.d_name[i];
433: return(0);
434: }
435:
436: ckroot(name)
437: char *name; {
438: register int i;
439: if(stat(y.d_name,&x) < 0)return;
440: i = x.st_dev;
441: if(chdir("/") < 0)return;
442: if((file = fopen("/","r")) == NULL)return;
443: do {
444: if(fread(&y,1,sizeof y,file) != sizeof y)return;
445: if(y.d_ino == 0)continue;
446: if(stat(y.d_name,&x) < 0)return;
447: } while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR);
448: if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0)
449: if(cat(name))return;
450: i = strlen(name);
451: name[i+1] = 0;
452: while(--i >= 0)name[i + 1] = name[i];
453: name[0] = '/';
454: return;
455: }
456: /*
457: this function takes a file name and tells whether it is a
458: directory or on. Returns 1 if so, 0 otherwise.
459: null strings etc. return 0.
460: */
461: isdirectory(fn)
462: char *fn;
463: {
464: int i,ret=0;
465: if(fn == NULL || *fn == 0)return(0);
466: i = strlen(fn);
467: if(i == 1){
468: if(strcmp(fn,".") == 0)ret = 1;
469: if(strcmp(fn,"/") == 0)ret = 1;
470: }
471: else if(i == 2){
472: if(strcmp(fn,"..") == 0)ret = 1;
473: if(strcmp(fn,"/.") == 0)ret = 1;
474: }
475: else {
476: if(strcmp(fn+i-2,"/.") == 0)ret = 1;
477: if(strcmp(fn+i-3,"/..") == 0)ret = 1;
478: }
479: return(ret);
480: }
481: /*
482: generate a variable parameter list
483: the format is:
484: (name value, name value, ..., name value)
485: where names are unquoted single words and values
486: are unquoted if a single alphanumeric word, and are
487: surrounded by {} otherwise. \ quotes { and }.
488: the values are escape-processed, e.g. \n becomes 012.
489: this function returns such a list.
490: Returns the null parm list if nothing to give, i.e. "()"
491:
492: Should also default so single keywords can have on/off
493: states, and so do not require a value.
494:
495: Things this variable protocol should specify:
496: EPASSWD encrypted passwd
497: FILEMODE file mode
498: FROMUID from users' uid
499: FROMGID from users' gid
500: COMPRESS use colin's compression
501: SPACCT handle special accounts.
502: MESSAGEID unique number identifying this request.
503: VTOUSERNAME name netq should display as being "To:"
504: FILENAME when omitted by netcp, will use FILENAME ext.
505: MACHINE2 a second machine (e.g. 3way netcp)
506: LOGIN2 a second login name
507: PASSWD2 a second passwd
508: REPLYTO the person the response should be sent to
509:
510: */
511: char *genparmlist(){
512: static char returnstr[PARMLIST];
513: strcpy(returnstr,"()");
514: return(returnstr);
515: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.