|
|
1.1 root 1: #include "netb.h"
2: #include "nberrno.h"
3: #include "rf.h"
4: #include "tag.h"
5:
6: #define NULL 0
7: extern char *strchr();
8: extern int defaultuid, defaultgid;
9: extern int cuid, cgid;
10:
11: #define ARB 4096
12:
13: /*
14: * netb-to-local service translation
15: */
16:
17: static long timeoff;
18: static timecheck();
19: static Rfile *root; /* should this be a global? */
20: static int nberrno;
21:
22: /*
23: * magic knowledge: fserrno and nberrno codes are the same
24: */
25: #define fstonberr(e) (e)
26:
27: /*
28: * compatibility with old clients
29: * that don't generate NBROOTTAG
30: */
31: static Tag oldrtag;
32: static int oldrdev;
33: #define OLDRINO 2L
34: static int oldclient; /* it used oldrtag */
35: static int sawroot;
36:
37: static Rfile *getfile();
38: static putmode();
39:
40: /*
41: * make a tag from a file
42: * the root is an exception; it has NBROOTTAG, always
43: * 0x80000000 is a temporary protection against confusion with oldrtag
44: */
45: #define maketag(f) (0x80000000|((f)->dev<<16)|((f)->ino&0xffff))
46:
47: /*
48: * file modes
49: * not specified in netb.h,
50: * but they are the same as V7 Unix
51: */
52:
53: #define NB_IFMT 0170000 /* file type */
54: #define NB_IFDIR 0040000 /* directory */
55: #define NB_IFREG 0100000 /* regular file */
56: #define NB_PERM 07777 /* permissions */
57:
58: #define fstonbmode(m) (m) /* other modes (assumed) same as rf */
59: #define nbtofsmode(m) ((m)&07777) /* modes that may be set */
60:
61: long time();
62:
63: /*
64: * init things;
65: * called before the connection is fully open
66: * mainly, set up the root
67: */
68:
69: int
70: _rfinit(argc, argv)
71: int argc;
72: char **argv;
73: {
74:
75: if ((root = fsinit(argc, argv)) == NULL) {
76: rflog("init failed\n");
77: return (0);
78: }
79: if (_rfnewtag((Tag)NBROOTTAG, root) != root) {
80: rflog("can't install root\n");
81: return (0);
82: }
83: return (1);
84: }
85:
86: /*
87: * namei
88: *
89: * hand the pathname to fswalk, a piece at a time
90: * on reaching the end, do the operation implied by SNB_FLAGS
91: * fswalk might return an Rfile that is already in our table;
92: * keep the older one.
93: * -- be careful when calling fsdone on intermediate directories
94: * in the path; they might be in use in some other way, and
95: * fsdone will wreak havoc.
96: * dirintab is there so _rfdone needn't be called every time,
97: * especially for directories we know are already in the table
98: */
99:
100: _rfnamei(fd, sp, len)
101: int fd;
102: unsigned char *sp;
103: int len;
104: {
105: unsigned char rbuf[RNMSIZE];
106: register unsigned char *pp;
107: register Rfile *f, *df;
108: Rfile *lnf;
109: int dirintab;
110: register char *cp, *ep;
111: Tag t;
112: int cruid, crgid, crmode;
113: long tm;
114:
115: nberrno = 0;
116: tonetchar(rbuf, RNB_FLAGS, 0);
117: pp = sp;
118: if (len < SNMSIZE)
119: rfpanic("namei: len %d\n", len);
120: pp[len] = 0; /* guarantee null at end of name */
121: cp = (char *)pp + SNMSIZE;
122: while (*cp == '/')
123: cp++;
124: dirintab = 1;
125: if ((df = getfile(&pp[SNB_TAG])) == NULL) {
126: nberrno = NBEINVAL;
127: goto out;
128: }
129: while ((ep = strchr(cp, '/')) != NULL) {
130: *ep++ = 0;
131: while (*ep == '/')
132: ep++;
133: if (df->type != RFTDIR) {
134: nberrno = NBENOENT;
135: goto out;
136: }
137: if (_rfpdsearch(df, rfuid, rfgid) == NULL) {
138: nberrno = NBEACCES;
139: goto out;
140: }
141: if ((f = fswalk(df, cp)) == NULL)
142: goto eout;
143: if (f != df && dirintab == 0)
144: fsdone(df);
145: if (f->ino == root->ino && f->dev == root->dev) {
146: if (f != root)
147: fsdone(f);
148: df = root;
149: dirintab = 1;
150: } else if ((df = _rftagtof(maketag(f))) != NULL) {
151: fsdone(f);
152: dirintab = 1;
153: } else {
154: df = f;
155: dirintab = 0;
156: }
157: cp = ep;
158: }
159: /*
160: * cp is now last component
161: *
162: * the tests that follow are wrong if the root isn't a directory
163: * think about implications
164: */
165: if (df->type != RFTDIR) {
166: nberrno = NBENOENT;
167: goto out;
168: }
169: if (_rfpdsearch(df, rfuid, rfgid) == 0) {
170: nberrno = NBEACCES;
171: goto out;
172: }
173: switch (frnetchar(pp, SNB_FLAGS)) {
174: case NI_SEARCH:
175: if (cp[0] == 0) { /* empty filename */
176: f = df;
177: fsstat(f); /* get fresh info */
178: break;
179: }
180: if ((f = fswalk(df, cp)) == NULL)
181: goto eout;
182: break;
183:
184: case NI_NXCREAT:
185: case NI_CREAT:
186: cruid = rfuid;
187: if (cruid == RFNOID && defaultuid != RFNOID)
188: cruid = defaultuid;
189: crgid = rfgid;
190: if (crgid == RFNOID && defaultgid != RFNOID)
191: crgid = defaultgid;
192: crmode = frnetshort(pp, SNM_MODE);
193: if ((f = fswalk(df, cp)) == NULL) { /* doesn't exist */
194: if (cruid == RFNOID || crgid == RFNOID /* don't create ownerless files */
195: || _rfpdwrite(df, cruid, crgid) == 0) {
196: nberrno = NBEACCES;
197: goto out;
198: }
199: } else if (frnetchar(pp, SNB_FLAGS) == NI_NXCREAT) {
200: _rfdone(f);
201: nberrno = NBEEXIST; /* NXCREAT means it shouldn't exist */
202: goto out;
203: } else {
204: if (_rfpwrite(f, cruid, crgid) == 0) {
205: _rfdone(f);
206: nberrno = NBEACCES;
207: goto out;
208: }
209: cruid = f->uid;
210: crgid = f->gid;
211: crmode = f->mode;
212: _rfdone(f); /* we'll re-create anyway */
213: }
214: if ((f = fscreate(df, cp, crmode, cruid, crgid)) == NULL)
215: goto eout;
216: break;
217:
218: case NI_LINK:
219: if ((lnf = getfile(&pp[SNM_INO])) == NULL) {
220: nberrno = NBEINVAL;
221: goto out;
222: }
223: #if NOTDEF
224: if (lnf->type == RFTDIR && _rfpsuper(lnf, rfuid, rfgid) == 0) {
225: #else
226: if (lnf->type == RFTDIR) {
227: #endif
228: nberrno = NBEISDIR;
229: goto out;
230: }
231: if (_rfpdwrite(df, rfuid, rfgid) == 0) {
232: nberrno = NBEACCES;
233: goto out;
234: }
235: if (fslink(df, cp, lnf) < 0)
236: goto eout;
237: goto out;
238:
239: case NI_MKDIR:
240: cruid = rfuid;
241: if (cruid == RFNOID && defaultuid != RFNOID)
242: cruid = defaultuid;
243: crgid = rfgid;
244: if (crgid == RFNOID && defaultgid != RFNOID)
245: crgid = defaultgid;
246: if (cruid == RFNOID || crgid == RFNOID
247: || _rfpdwrite(df, cruid, crgid) == 0) {
248: nberrno = NBEACCES;
249: goto out;
250: }
251: if (fsmkdir(df, cp, frnetshort(pp, SNM_MODE), cruid, crgid) < 0)
252: goto eout;
253: goto out;
254:
255: case NI_RMDIR:
256: if (_rfpdwrite(df, rfuid, rfgid) == 0) {
257: nberrno = NBEACCES;
258: goto out;
259: }
260: if (fsrmdir(df, cp) < 0)
261: goto eout;
262: goto out;
263:
264: case NI_DEL:
265: if (_rfpdwrite(df, rfuid, rfgid) == 0) {
266: nberrno = NBEACCES;
267: goto out;
268: }
269: if ((f = fswalk(df, cp)) == NULL)
270: goto eout;
271: #if NOTDEF
272: if (f->type == RFTDIR && _rfpsuper(f, rfuid, rfgid) == 0) {
273: #else
274: if (f->type == RFTDIR) {
275: #endif
276: _rfdone(f);
277: nberrno = NBEISDIR;
278: goto out;
279: }
280: _rfdone(f);
281: if (fsdelete(df, cp) < 0)
282: goto eout;
283: goto out;
284:
285: default:
286: nberrno = NBEINVAL;
287: goto out;
288: }
289: /*
290: * returning a newly-opened file
291: */
292: if (f->dev == root->dev && f->ino == root->ino)
293: t = NBROOTTAG;
294: else
295: t = maketag(f);
296: if ((lnf = _rfnewtag(t, f)) == NULL) {
297: fsdone(f);
298: nberrno = NBEINVAL;
299: goto out;
300: } else if (lnf != f) { /* already had that file */
301: fsdone(f);
302: f = lnf;
303: }
304: if (f == df)
305: dirintab = 1; /* we just made sure of that */
306: pp = rbuf;
307: tonetlong(pp, RNM_TAG, t);
308: tonetlong(pp, RNM_INO, f->ino);
309: tonetshort(pp, RNM_DEV, f->dev);
310: putmode(pp, RNM_MODE, f);
311: tonetshort(pp, RNM_NLINK, f->nlink);
312: /*
313: * the default ownership here might be wrong...check it.
314: */
315: if (defaultuid != RFNOID && rfuid == RFNOID && f->uid == defaultuid)
316: len = cuid; /* tell him he owns it */
317: else
318: len = _rfcuid(f->uid);
319: tonetshort(pp, RNM_UID, len);
320: len = _rfcgid(f->gid); /* stub - this gid processing may be wrong */
321: if (len == RFNOID)
322: len = cgid;
323: tonetshort(pp, RNM_GID, len);
324: tonetshort(pp, RNM_RDEV, f->rdev);
325: #if 0x100000000 == 0 /* 32-bit machine */
326: tonetlong(pp, RNM_SIZE, f->size);
327: #else /* probably the Cray */
328: if ((tm = f->size) > 0x7fffffff)
329: tm = 0x7fffffff;
330: tonetlong(pp, RNM_SIZE, tm);
331: #endif
332: tm = f->ta + timeoff;
333: tonetlong(pp, RNM_ATIME, tm);
334: tm = f->tm + timeoff;
335: tonetlong(pp, RNM_MTIME, tm);
336: tm = f->tc + timeoff;
337: tonetlong(pp, RNM_CTIME, tm);
338: if (oldclient) {
339: len = (f->dev & 0xff) | (oldrdev & 0xff00);
340: tonetshort(pp, RNM_DEV, len);
341: if (f == root) {
342: tonetlong(pp, RNM_TAG, oldrtag);
343: tonetshort(pp, RNM_DEV, oldrdev);
344: tonetlong(pp, RNM_INO, OLDRINO);
345: }
346: }
347: goto out;
348:
349: /*
350: * failed to find a file
351: * if nberrno == 0, popped out of root
352: */
353: eout:
354: if (fserrno)
355: nberrno = fstonberr(fserrno);
356: else {
357: nberrno = 0;
358: tonetchar(rbuf, RNB_FLAGS, NBROOT);
359: while (*cp && *cp != '/')
360: cp++;
361: len = cp - (char *)(sp + SNMSIZE);
362: if (rfdebug)
363: rflog("popped out; used %d\n", len);
364: tonetlong(rbuf, RNM_USED, len);
365: }
366: /*
367: * done
368: */
369: out:
370: if (dirintab == 0)
371: _rfdone(df);
372: tonetshort(rbuf, RNB_ERRNO, nberrno);
373: _rfresp(fd, sp, rbuf, RNMSIZE);
374: }
375:
376: /*
377: * discard f if it is not in the tag table
378: * used by rfnamei to discard files fetched halfway,
379: * e.g. directories in the middle of a path
380: */
381:
382: _rfdone(f)
383: register Rfile *f;
384: {
385:
386: if (f == root)
387: return;
388: if (_rftagtof(maketag(f)) == f)
389: return;
390: fsdone(f);
391: }
392:
393: /*
394: * put
395: */
396:
397: _rfput(fd, sp, len)
398: int fd;
399: register unsigned char *sp;
400: int len;
401: {
402: unsigned char rbuf[RNBSIZE];
403: Tag t;
404: Rfile *f;
405:
406: t = frnetlong(sp, SNB_TAG);
407: if ((f = getfile(&sp[SNB_TAG])) == NULL)
408: nberrno = NBEINVAL;
409: else {
410: _rfdeltag(t);
411: nberrno = 0;
412: fsdone(f);
413: }
414: tonetshort(rbuf, RNB_ERRNO, nberrno);
415: _rfresp(fd, sp, rbuf, RNBSIZE);
416: }
417:
418: /*
419: * stat
420: */
421:
422: _rfstat(fd, sp, len)
423: int fd;
424: unsigned char *sp;
425: int len;
426: {
427: int i;
428: unsigned char rbuf[RSTSIZE];
429: register unsigned char *rp;
430: register Rfile *f;
431: long tm;
432:
433: if (len < SSTSIZE)
434: rfpanic("stat: len %d\n", len);
435: rp = rbuf;
436: if ((f = getfile(&sp[SNB_TAG])) == NULL)
437: nberrno = NBEINVAL;
438: else if (fsstat(f) < 0)
439: nberrno = fstonberr(fserrno);
440: else {
441: nberrno = 0;
442: /* should have hysteresis here */
443: timecheck(frnetlong(sp, SST_TIME));
444: tonetlong(rp, RST_INO, f->ino);
445: tonetshort(rp, RST_DEV, f->dev);
446: putmode(rp, RST_MODE, f);
447: tonetshort(rp, RST_NLINK, f->nlink);
448: if (defaultuid != RFNOID && rfuid == RFNOID && f->uid == defaultuid)
449: i = cuid; /* let the client think he owns it */
450: else
451: i = _rfcuid(f->uid);
452: /*rflog("stat: f->uid=%d defaultuid=%d cuid=%d rfcuid=%d returning %d\n",
453: f->uid, defaultuid, cuid, _rfcuid(f->uid), i);*/
454: tonetshort(rp, RST_UID, i);
455: i = _rfcgid(f->gid); /* stub - default gid processing? */
456: tonetshort(rp, RST_GID, i);
457: #if 0x100000000 == 0 /* 32-bit machine */
458: tonetlong(rp, RST_SIZE, f->size);
459: #else /* probably the Cray */
460: if ((tm = f->size) > 0x7fffffff)
461: tm = 0x7fffffff;
462: tonetlong(rp, RST_SIZE, f->size);
463: #endif
464: tm = f->ta + timeoff;
465: tonetlong(rp, RST_ATIME, tm);
466: tm = f->tm + timeoff;
467: tonetlong(rp, RST_MTIME, tm);
468: tm = f->tc + timeoff;
469: tonetlong(rp, RST_CTIME, tm);
470: }
471: tonetshort(rp, RNB_ERRNO, nberrno);
472: _rfresp(fd, sp, rp, RSTSIZE);
473: }
474:
475: /*
476: * update:
477: * write attributes
478: */
479:
480: _rfupdate(fd, sp, len)
481: int fd;
482: register unsigned char *sp;
483: int len;
484: {
485: unsigned char rbuf[RNBSIZE];
486: static Rfile na;
487: Rfile *f;
488:
489: if (len < SUPSIZE)
490: rfpanic("update: len %d\n", len);
491: if ((f = getfile(&sp[SNB_TAG])) == NULL)
492: nberrno = NBEINVAL;
493: else {
494: na.mode = nbtofsmode(frnetshort(sp, SUP_MODE));
495: na.ta = frnetlong(sp, SUP_ATIME);
496: na.tm = frnetlong(sp, SUP_MTIME);
497: if (na.ta == 0) /* current time: local system did it */
498: na.ta = f->ta;
499: else
500: na.ta -= timeoff;
501: if (na.tm == 0)
502: na.tm = f->tm;
503: else
504: na.tm -= timeoff;
505: na.uid = f->uid; /* netb doesn't supply */
506: na.gid = f->gid;
507: na.size = f->size; /* not set here */
508: if ((na.mode & NB_PERM) != (fstonbmode(f->mode) & NB_PERM)
509: && _rfpowner(f, rfuid, rfgid) == 0)
510: nberrno = NBEPERM;
511: else if (fsupdate(f, &na) < 0)
512: nberrno = fstonberr(fserrno);
513: else
514: nberrno = 0;
515: }
516: tonetshort(rbuf, RNB_ERRNO, nberrno);
517: _rfresp(fd, sp, rbuf, RNBSIZE);
518: }
519:
520: /*
521: * read
522: */
523: _rfread(fd, sp, mlen)
524: int fd;
525: register unsigned char *sp;
526: int mlen;
527: {
528: unsigned char rbuf[RNBSIZE+ARB]; /* should be negotiated size */
529: Rfile *f;
530: int len;
531:
532: if (mlen < SRDSIZE)
533: rfpanic("read: len %d\n", mlen);
534: len = frnetlong(sp, SRD_LEN);
535: tonetchar(rbuf, RNB_FLAGS, 0);
536: if (len <= 0 || (f = getfile(&sp[SNB_TAG])) == NULL) {
537: nberrno = NBEINVAL;
538: len = 0;
539: } else if (_rfpread(f, rfuid, rfgid) == 0) {
540: nberrno = NBEACCES;
541: len = 0;
542: } else {
543: if (len > ARB)
544: len = ARB;
545: len = fsread(f, frnetlong(sp, SRD_OFFSET),
546: (char *)rbuf + RNBSIZE, len);
547: if (len < 0) {
548: nberrno = fstonberr(fserrno);
549: len = 0;
550: } else {
551: nberrno = 0;
552: if (len == 0)
553: tonetchar(rbuf, RNB_FLAGS, NBEND);
554: }
555: }
556: tonetshort(rbuf, RNB_ERRNO, nberrno);
557: len += RNBSIZE;
558: _rfresp(fd, sp, rbuf, len);
559: }
560:
561: /*
562: * read directory
563: */
564: _rfdir(fd, sp, mlen)
565: int fd;
566: register unsigned char *sp;
567: int mlen;
568: {
569: unsigned char rbuf[RDISIZE+ARB];
570: Rfile *f;
571: int len;
572: long noff;
573:
574: if (mlen < SRDSIZE)
575: rfpanic("readdir: len %d\n", mlen);
576: len = frnetlong(sp, SRD_LEN);
577: if (len <= 0 || (f = getfile(&sp[SNB_TAG])) == NULL) {
578: nberrno = NBEINVAL;
579: len = 0;
580: } else if (f->type != RFTDIR) {
581: nberrno = NBENOTDIR;
582: len = 0;
583: } else if (_rfpdread(f, rfuid, rfgid) == 0) {
584: nberrno = NBEACCES;
585: len = 0;
586: } else {
587: if (len > ARB)
588: len = ARB;
589: len = fsdirread(f, frnetlong(sp, SRD_OFFSET),
590: (char *)rbuf + RDISIZE, len, &noff);
591: if (len < 0) {
592: nberrno = fstonberr(fserrno);
593: len = 0;
594: } else {
595: nberrno = 0;
596: noff -= frnetlong(sp, SRD_OFFSET);
597: tonetlong(rbuf, RDI_USED, noff);
598: }
599: }
600: tonetshort(rbuf, RNB_ERRNO, nberrno);
601: len += RDISIZE;
602: _rfresp(fd, sp, rbuf, len);
603: }
604:
605: /*
606: * write
607: * --permissions botch:
608: * if we just check for write permission,
609: * f = creat(name, 0) will leave a file descriptor we can't write
610: * hence the owner check
611: * if the client wants to protect the user better,
612: * it can do its own checks;
613: * here we are concerned with the server
614: */
615: _rfwrite(fd, sp, mlen)
616: int fd;
617: register unsigned char *sp;
618: int mlen;
619: {
620: unsigned char rbuf[RNBSIZE];
621: Rfile *f;
622: int n;
623: long off;
624:
625: n = frnetlong(sp, SWR_LEN);
626: if (mlen != SWRSIZE + n)
627: rfpanic("write: size skew %d\n", mlen);
628: off = frnetlong(sp, SWR_OFFSET);
629: nberrno = 0;
630: if ((f = getfile(&sp[SNB_TAG])) == NULL)
631: nberrno = NBEINVAL;
632: else if (_rfpwrite(f, rfuid, rfgid) == 0
633: && _rfpowner(f, rfuid, rfgid) == 0)
634: nberrno = NBEACCES;
635: else if ((n = fswrite(f, off, (char *)sp + SWRSIZE, n)) < 0)
636: nberrno = fstonberr(fserrno);
637: tonetlong(rbuf, RNB_FSIZE, f->size);
638: tonetshort(rbuf, RNB_ERRNO, nberrno);
639: _rfresp(fd, sp, rbuf, RNBSIZE);
640: }
641:
642: /*
643: * truncate file
644: */
645: _rftrunc(fd, sp, len)
646: int fd;
647: register unsigned char *sp;
648: int len;
649: {
650: unsigned char rbuf[RNBSIZE];
651: register Rfile *f;
652: Rfile newf;
653:
654: nberrno = 0;
655: if ((f = getfile(&sp[SNB_TAG])) == NULL)
656: nberrno = NBEINVAL;
657: else if (_rfpwrite(f, rfuid, rfgid) == 0
658: && _rfpowner(f, rfuid, rfgid) == 0) /* wrong? */
659: nberrno = NBEACCES;
660: else {
661: newf = *f;
662: newf.size = 0;
663: if (fsupdate(f, &newf) < 0)
664: nberrno = fstonberr(fserrno);
665: }
666: tonetlong(rbuf, RNB_ERRNO, nberrno);
667: _rfresp(fd, sp, rbuf, RNBSIZE);
668: }
669:
670: /*
671: * turn SNB_TAG (or some other tag)
672: * into an Rfile
673: */
674:
675: static Rfile *
676: getfile(pp)
677: register unsigned char *pp;
678: {
679: Tag t;
680: Rfile *f;
681:
682: t = frnetlong(pp, 0);
683: if (t == NBROOTTAG || (oldclient && t == oldrtag)) {
684: sawroot = 1;
685: return (root); /* easy */
686: }
687: if ((f = _rftagtof(t)) != NULL)
688: return (f);
689: if (sawroot == 0 && (t & 0xffff) == OLDRINO) { /* old-style root tag? */
690: oldrtag = t;
691: oldrdev = t >> 16;
692: oldclient = 1;
693: rflog("old client; root tag %lx\n", t);
694: sawroot = 1;
695: return (root);
696: }
697: nberrno = NBEINVAL; /* shouldn't happen */
698: rflog("bad tag %lx\n", t);
699: return (NULL);
700: }
701:
702: static
703: putmode(pp, off, f)
704: register unsigned char *pp;
705: int off;
706: register Rfile *f;
707: {
708: int mode;
709:
710: mode = fstonbmode(f->mode);
711: if (f->type == RFTDIR) {
712: mode &= 07777;
713: mode |= NB_IFDIR;
714: } else if ((mode & NB_IFMT) == 0)
715: mode |= NB_IFREG;
716: /* else pass mode through unchanged for now */
717: tonetshort(pp, off, mode);
718: }
719:
720: /*
721: * correct offset twixt client time and ours
722: * only so often, or if difference is large;
723: * e.g. hosts synchronize from a common clock,
724: * but at different times
725: */
726:
727: static
728: timecheck(cltime)
729: long cltime;
730: {
731: static int stall;
732: static long lastck;
733: long ourtime;
734: int diff;
735:
736: if (stall-- != 0) /* only every few stats */
737: return;
738: stall = 3;
739: ourtime = time((long *)0);
740: diff = cltime - ourtime;
741: if (diff == timeoff) {
742: lastck = ourtime;
743: return; /* no change */
744: }
745: if (diff - timeoff < 2 && diff - timeoff > -2 /* modest change */
746: && ourtime - lastck < 90*60) /* and last change was recent */
747: return;
748: lastck = ourtime;
749: rflog("time: client %ld server %ld old diff %d new %d\n",
750: cltime, ourtime, timeoff, diff);
751: timeoff = diff;
752: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.