1 #include "ratfs.h"
2 #include <ip.h>
3
4 enum {
5 Maxdoms = 10, /* max domains in a path */
6 Timeout = 2*60*60, /* seconds until temporarily trusted addr times out */
7 };
8
9 static int accountmatch(char*, char**, int, char*);
10 static Node* acctwalk(char*, Node*);
11 static int dommatch(char*, char*);
12 static Address* ipsearch(ulong, Address*, int);
13 static Node* ipwalk(char*, Node*);
14 static Node* trwalk(char*, Node*);
15 static int usermatch(char*, char*);
16
17 /*
18 * Do a walk
19 */
20 char*
walk(char * name,Fid * fidp)21 walk(char *name, Fid *fidp)
22 {
23 Node *np;
24
25 if((fidp->node->d.mode & DMDIR) == 0)
26 return "not a directory";
27
28 if(strcmp(name, ".") == 0)
29 return 0;
30 if(strcmp(name, "..") == 0){
31 fidp->node = fidp->node->parent;
32 fidp->name = 0;
33 return 0;
34 }
35
36 switch(fidp->node->d.type){
37 case Directory:
38 case Addrdir:
39 np = dirwalk(name, fidp->node);
40 break;
41 case Trusted:
42 np = trwalk(name, fidp->node);
43 break;
44 case IPaddr:
45 np = ipwalk(name, fidp->node);
46 break;
47 case Acctaddr:
48 np = acctwalk(name, fidp->node);
49 break;
50 default:
51 return "directory botch in walk";
52 }
53 if(np) {
54 fidp->node = np;
55 fidp->name = np->d.name;
56 return 0;
57 }
58 return "file does not exist";
59 }
60
61 /*
62 * Walk to a subdirectory
63 */
64 Node*
dirwalk(char * name,Node * np)65 dirwalk(char *name, Node *np)
66 {
67 Node *p;
68
69 for(p = np->children; p; p = p->sibs)
70 if(strcmp(name, p->d.name) == 0)
71 break;
72 return p;
73 }
74
75 /*
76 * Walk the directory of trusted files
77 */
78 static Node*
trwalk(char * name,Node * np)79 trwalk(char *name, Node *np)
80 {
81 Node *p;
82 ulong peerip;
83 uchar addr[IPv4addrlen];
84
85 v4parseip(addr, name);
86 peerip = nhgetl(addr);
87
88 for(p = np->children; p; p = p->sibs)
89 if((peerip&p->ip.mask) == p->ip.ipaddr)
90 break;
91 return p;
92 }
93
94 /*
95 * Walk a directory of IP addresses
96 */
97 static Node*
ipwalk(char * name,Node * np)98 ipwalk(char *name, Node *np)
99 {
100 Address *ap;
101 ulong peerip;
102 uchar addr[IPv4addrlen];
103
104 v4parseip(addr, name);
105 peerip = nhgetl(addr);
106
107 if(debugfd >= 0)
108 fprint(debugfd, "%d.%d.%d.%d - ", addr[0]&0xff, addr[1]&0xff,
109 addr[2]&0xff, addr[3]&0xff);
110 ap = ipsearch(peerip, np->addrs, np->count);
111 if(ap == 0)
112 return 0;
113
114 dummy.d.name = ap->name;
115 return &dummy;
116 }
117
118 /*
119 * Walk a directory of account names
120 */
121 static Node*
acctwalk(char * name,Node * np)122 acctwalk(char *name, Node *np)
123 {
124 int i, n;
125 Address *ap;
126 char *p, *cp, *user;
127 char buf[512];
128 char *doms[Maxdoms];
129
130 strecpy(buf, buf+sizeof buf, name);
131 subslash(buf);
132
133 p = buf;
134 for(n = 0; n < Maxdoms; n++) {
135 cp = strchr(p, '!');
136 if(cp == 0)
137 break;
138 *cp = 0;
139 doms[n] = p;
140 p = cp+1;
141 }
142 user = p;
143
144 for(i = 0; i < np->count; i++){
145 ap = &np->addrs[i];
146 if (accountmatch(ap->name, doms, n, user)) {
147 dummy.d.name = ap->name;
148 return &dummy;
149 }
150 }
151 return 0;
152 }
153
154 /*
155 * binary search sorted IP address list
156 */
157
158 static Address*
ipsearch(ulong addr,Address * base,int n)159 ipsearch(ulong addr, Address *base, int n)
160 {
161 ulong top, bot, mid;
162 Address *ap;
163
164 bot = 0;
165 top = n;
166 for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
167 ap = &base[mid];
168 if((addr&ap->ip.mask) == ap->ip.ipaddr)
169 return ap;
170 if(addr < ap->ip.ipaddr)
171 top = mid;
172 else if(mid != n-1 && addr >= base[mid+1].ip.ipaddr)
173 bot = mid;
174 else
175 break;
176 }
177 return 0;
178 }
179
180 /*
181 * Read a directory
182 */
183 int
dread(Fid * fidp,int cnt)184 dread(Fid *fidp, int cnt)
185 {
186 uchar *q, *eq, *oq;
187 int n, skip;
188 Node *np;
189
190 if(debugfd >= 0)
191 fprint(debugfd, "dread %d\n", cnt);
192
193 np = fidp->node;
194 oq = q = rbuf+IOHDRSZ;
195 eq = q+cnt;
196 if(fidp->dirindex >= np->count)
197 return 0;
198
199 skip = fidp->dirindex;
200 for(np = np->children; skip > 0 && np; np = np->sibs)
201 skip--;
202 if(np == 0)
203 return 0;
204
205 for(; q < eq && np; np = np->sibs){
206 if(debugfd >= 0)
207 printnode(np);
208 if((n=convD2M(&np->d, q, eq-q)) <= BIT16SZ)
209 break;
210 q += n;
211 fidp->dirindex++;
212 }
213 return q - oq;
214 }
215
216 /*
217 * Read a directory of IP addresses or account names
218 */
219 int
hread(Fid * fidp,int cnt)220 hread(Fid *fidp, int cnt)
221 {
222 uchar *q, *eq, *oq;
223 int i, n, path;
224 Address *p;
225 Node *np;
226
227 if(debugfd >= 0)
228 fprint(debugfd, "hread %d\n", cnt);
229
230 np = fidp->node;
231 oq = q = rbuf+IOHDRSZ;
232 eq = q+cnt;
233 if(fidp->dirindex >= np->count)
234 return 0;
235
236 path = np->baseqid;
237 for(i = fidp->dirindex; q < eq && i < np->count; i++){
238 p = &np->addrs[i];
239 dummy.d.name = p->name;
240 dummy.d.qid.path = path++;
241 if((n=convD2M(&dummy.d, q, eq-q)) <= BIT16SZ)
242 break;
243 q += n;
244 }
245 fidp->dirindex = i;
246 return q - oq;
247 }
248
249 /*
250 * Find a directory node by type
251 */
252 Node*
finddir(int type)253 finddir(int type)
254 {
255 Node *np;
256
257 for(np = root->children; np; np = np->sibs)
258 if (np->d.type == type)
259 return np;
260 return 0;
261 }
262
263 /*
264 * Remove temporary pseudo-files that have timed-out
265 * from the trusted directory
266 */
267 void
cleantrusted(void)268 cleantrusted(void)
269 {
270 Node *np, **l;
271 ulong t;
272
273 np = finddir(Trusted);
274 if (np == 0)
275 return;
276
277 t = time(0)-Timeout;
278 l = &np->children;
279 for (np = np->children; np; np = *l) {
280 if(np->d.type == Trustedtemp && t >= np->d.mtime) {
281 *l = np->sibs;
282 if(debugfd >= 0)
283 fprint(debugfd, "Deleting %s\n", np->d.name);
284 np->parent->count--;
285 free(np);
286 } else
287 l = &np->sibs;
288 }
289 }
290
291 /*
292 * match path components to prohibited domain & user specifications. patterns include:
293 * domain, domain! or domain!* - all users in domain
294 * *.domain, *.domain! or *.domain!* - all users in domain and its subdomains
295 * !user or *!user - user in all domains
296 * domain!user - user in domain
297 * *.domain!user - user in domain and its subdomains
298 *
299 * if "user" has a trailing '*', it matches all user names beginning with "user"
300 *
301 * there are special semantics for the "domain, domain! or domain!*" specifications:
302 * the first two forms match when the domain is anywhere in at list of source-routed
303 * domains while the latter matches only when the domain is the last hop. the same is
304 * true for the *.domain!* form of the pattern.
305 */
306 static int
accountmatch(char * spec,char ** doms,int ndoms,char * user)307 accountmatch(char *spec, char **doms, int ndoms, char *user)
308 {
309 char *cp, *userp;
310 int i, ret;
311
312 userp = 0;
313 ret = 0;
314 cp = strchr(spec, '!');
315 if(cp){
316 *cp++ = 0; /* restored below */
317 if(*cp)
318 if(strcmp(cp, "*")) /* "!*" is the same as no user field */
319 userp = cp; /* there is a user name */
320 }
321
322 if(userp == 0){ /* no user field - domain match only */
323 for(i = 0; i < ndoms && doms[i]; i++)
324 if(dommatch(doms[i], spec) == 0)
325 ret = 1;
326 } else {
327 /* check for "!user", "*!user" or "domain!user" */
328 if(usermatch(user, userp) == 0){
329 if(*spec == 0 || strcmp(spec, "*") == 0)
330 ret = 1;
331 else if(ndoms > 0 && dommatch(doms[ndoms-1], spec) == 0)
332 ret = 1;
333 }
334 }
335 if(cp)
336 cp[-1] = '!';
337 return ret;
338 }
339
340 /*
341 * match a user name. the only meta-char is '*' which matches all
342 * characters. we only allow it as "*", which matches anything or
343 * an * at the end of the name (e.g., "username*") which matches
344 * trailing characters.
345 */
346 static int
usermatch(char * pathuser,char * specuser)347 usermatch(char *pathuser, char *specuser)
348 {
349 int n;
350
351 n = strlen(specuser)-1;
352 if(specuser[n] == '*'){
353 if(n == 0) /* match everything */
354 return 0;
355 return strncmp(pathuser, specuser, n);
356 }
357 return strcmp(pathuser, specuser);
358 }
359
360 /*
361 * Match a domain specification
362 */
363 static int
dommatch(char * pathdom,char * specdom)364 dommatch(char *pathdom, char *specdom)
365 {
366 int n;
367
368 if (*specdom == '*'){
369 if (specdom[1] == '.' && specdom[2]){
370 specdom += 2;
371 n = strlen(pathdom)-strlen(specdom);
372 if(n == 0 || (n > 0 && pathdom[n-1] == '.'))
373 return strcmp(pathdom+n, specdom);
374 return n;
375 }
376 }
377 return strcmp(pathdom, specdom);
378 }
379
380 /*
381 * Custom allocators to avoid malloc overheads on small objects.
382 * We never free these. (See below.)
383 */
384 typedef struct Stringtab Stringtab;
385 struct Stringtab {
386 Stringtab *link;
387 char *str;
388 };
389 static Stringtab*
taballoc(void)390 taballoc(void)
391 {
392 static Stringtab *t;
393 static uint nt;
394
395 if(nt == 0){
396 t = malloc(64*sizeof(Stringtab));
397 if(t == 0)
398 fatal("out of memory");
399 nt = 64;
400 }
401 nt--;
402 return t++;
403 }
404
405 static char*
xstrdup(char * s)406 xstrdup(char *s)
407 {
408 char *r;
409 int len;
410 static char *t;
411 static int nt;
412
413 len = strlen(s)+1;
414 if(len >= 8192)
415 fatal("strdup big string");
416
417 if(nt < len){
418 t = malloc(8192);
419 if(t == 0)
420 fatal("out of memory");
421 nt = 8192;
422 }
423 r = t;
424 t += len;
425 nt -= len;
426 strcpy(r, s);
427 return r;
428 }
429
430 /*
431 * Return a uniquely allocated copy of a string.
432 * Don't free these -- they stay in the table for the
433 * next caller who wants that particular string.
434 * String comparison can be done with pointer comparison
435 * if you know both strings are atoms.
436 */
437 static Stringtab *stab[1024];
438
439 static uint
hash(char * s)440 hash(char *s)
441 {
442 uint h;
443 uchar *p;
444
445 h = 0;
446 for(p=(uchar*)s; *p; p++)
447 h = h*37 + *p;
448 return h;
449 }
450
451 char*
atom(char * str)452 atom(char *str)
453 {
454 uint h;
455 Stringtab *tab;
456
457 h = hash(str) % nelem(stab);
458 for(tab=stab[h]; tab; tab=tab->link)
459 if(strcmp(str, tab->str) == 0)
460 return tab->str;
461
462 tab = taballoc();
463 tab->str = xstrdup(str);
464 tab->link = stab[h];
465 stab[h] = tab;
466 return tab->str;
467 }
468