Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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*
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*
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*
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*
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*
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*
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
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
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*
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
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
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
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
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*
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*
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
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*
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
}