123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "ratfs.h"
- #include <ip.h>
- enum {
- Maxdoms = 10, /* max domains in a path */
- Timeout = 2*60*60, /* seconds until temporarily trusted addr times out */
- };
- static int accountmatch(char*, char**, int, char*);
- static Node* acctwalk(char*, Node*);
- static int dommatch(char*, char*);
- static Address* ipsearch(uint32_t, Address*, int);
- static Node* ipwalk(char*, Node*);
- static Node* trwalk(char*, Node*);
- static int usermatch(char*, char*);
- /*
- * Do a walk
- */
- char*
- walk(char *name, Fid *fidp)
- {
- Node *np;
- if((fidp->node->d.mode & DMDIR) == 0)
- return "not a directory";
- if(strcmp(name, ".") == 0)
- return 0;
- if(strcmp(name, "..") == 0){
- fidp->node = fidp->node->parent;
- fidp->name = 0;
- return 0;
- }
- switch(fidp->node->d.type){
- case Directory:
- case Addrdir:
- np = dirwalk(name, fidp->node);
- break;
- case Trusted:
- np = trwalk(name, fidp->node);
- break;
- case IPaddr:
- np = ipwalk(name, fidp->node);
- break;
- case Acctaddr:
- np = acctwalk(name, fidp->node);
- break;
- default:
- return "directory botch in walk";
- }
- if(np) {
- fidp->node = np;
- fidp->name = np->d.name;
- return 0;
- }
- return "file does not exist";
- }
- /*
- * Walk to a subdirectory
- */
- Node*
- dirwalk(char *name, Node *np)
- {
- Node *p;
- for(p = np->children; p; p = p->sibs)
- if(strcmp(name, p->d.name) == 0)
- break;
- return p;
- }
- /*
- * Walk the directory of trusted files
- */
- static Node*
- trwalk(char *name, Node *np)
- {
- Node *p;
- uint32_t peerip;
- uint8_t addr[IPv4addrlen];
- v4parseip(addr, name);
- peerip = nhgetl(addr);
- for(p = np->children; p; p = p->sibs)
- if((peerip&p->ip.mask) == p->ip.ipaddr)
- break;
- return p;
- }
- /*
- * Walk a directory of IP addresses
- */
- static Node*
- ipwalk(char *name, Node *np)
- {
- Address *ap;
- uint32_t peerip;
- uint8_t addr[IPv4addrlen];
- v4parseip(addr, name);
- peerip = nhgetl(addr);
- if(debugfd >= 0)
- fprint(debugfd, "%d.%d.%d.%d - ", addr[0]&0xff, addr[1]&0xff,
- addr[2]&0xff, addr[3]&0xff);
- ap = ipsearch(peerip, np->addrs, np->count);
- if(ap == 0)
- return 0;
- dummy.d.name = ap->name;
- return &dummy;
- }
- /*
- * Walk a directory of account names
- */
- static Node*
- acctwalk(char *name, Node *np)
- {
- int i, n;
- Address *ap;
- char *p, *cp, *user;
- char buf[512];
- char *doms[Maxdoms];
- strecpy(buf, buf+sizeof buf, name);
- subslash(buf);
- p = buf;
- for(n = 0; n < Maxdoms; n++) {
- cp = strchr(p, '!');
- if(cp == 0)
- break;
- *cp = 0;
- doms[n] = p;
- p = cp+1;
- }
- user = p;
- for(i = 0; i < np->count; i++){
- ap = &np->addrs[i];
- if (accountmatch(ap->name, doms, n, user)) {
- dummy.d.name = ap->name;
- return &dummy;
- }
- }
- return 0;
- }
- /*
- * binary search sorted IP address list
- */
- static Address*
- ipsearch(uint32_t addr, Address *base, int n)
- {
- uint32_t top, bot, mid;
- Address *ap;
- bot = 0;
- top = n;
- for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
- ap = &base[mid];
- if((addr&ap->ip.mask) == ap->ip.ipaddr)
- return ap;
- if(addr < ap->ip.ipaddr)
- top = mid;
- else if(mid != n-1 && addr >= base[mid+1].ip.ipaddr)
- bot = mid;
- else
- break;
- }
- return 0;
- }
- /*
- * Read a directory
- */
- int
- dread(Fid *fidp, int cnt)
- {
- uint8_t *q, *eq, *oq;
- int n, skip;
- Node *np;
- if(debugfd >= 0)
- fprint(debugfd, "dread %d\n", cnt);
- np = fidp->node;
- oq = q = rbuf+IOHDRSZ;
- eq = q+cnt;
- if(fidp->dirindex >= np->count)
- return 0;
- skip = fidp->dirindex;
- for(np = np->children; skip > 0 && np; np = np->sibs)
- skip--;
- if(np == 0)
- return 0;
- for(; q < eq && np; np = np->sibs){
- if(debugfd >= 0)
- printnode(np);
- if((n=convD2M(&np->d, q, eq-q)) <= BIT16SZ)
- break;
- q += n;
- fidp->dirindex++;
- }
- return q - oq;
- }
- /*
- * Read a directory of IP addresses or account names
- */
- int
- hread(Fid *fidp, int cnt)
- {
- uint8_t *q, *eq, *oq;
- int i, n, path;
- Address *p;
- Node *np;
- if(debugfd >= 0)
- fprint(debugfd, "hread %d\n", cnt);
- np = fidp->node;
- oq = q = rbuf+IOHDRSZ;
- eq = q+cnt;
- if(fidp->dirindex >= np->count)
- return 0;
- path = np->baseqid;
- for(i = fidp->dirindex; q < eq && i < np->count; i++){
- p = &np->addrs[i];
- dummy.d.name = p->name;
- dummy.d.qid.path = path++;
- if((n=convD2M(&dummy.d, q, eq-q)) <= BIT16SZ)
- break;
- q += n;
- }
- fidp->dirindex = i;
- return q - oq;
- }
- /*
- * Find a directory node by type
- */
- Node*
- finddir(int type)
- {
- Node *np;
- for(np = root->children; np; np = np->sibs)
- if (np->d.type == type)
- return np;
- return 0;
- }
- /*
- * Remove temporary pseudo-files that have timed-out
- * from the trusted directory
- */
- void
- cleantrusted(void)
- {
- Node *np, **l;
- uint32_t t;
- np = finddir(Trusted);
- if (np == 0)
- return;
- t = time(0)-Timeout;
- l = &np->children;
- for (np = np->children; np; np = *l) {
- if(np->d.type == Trustedtemp && t >= np->d.mtime) {
- *l = np->sibs;
- if(debugfd >= 0)
- fprint(debugfd, "Deleting %s\n", np->d.name);
- np->parent->count--;
- free(np);
- } else
- l = &np->sibs;
- }
- }
- /*
- * match path components to prohibited domain & user specifications. patterns include:
- * domain, domain! or domain!* - all users in domain
- * *.domain, *.domain! or *.domain!* - all users in domain and its subdomains
- * !user or *!user - user in all domains
- * domain!user - user in domain
- * *.domain!user - user in domain and its subdomains
- *
- * if "user" has a trailing '*', it matches all user names beginning with "user"
- *
- * there are special semantics for the "domain, domain! or domain!*" specifications:
- * the first two forms match when the domain is anywhere in at list of source-routed
- * domains while the latter matches only when the domain is the last hop. the same is
- * true for the *.domain!* form of the pattern.
- */
- static int
- accountmatch(char *spec, char **doms, int ndoms, char *user)
- {
- char *cp, *userp;
- int i, ret;
- userp = 0;
- ret = 0;
- cp = strchr(spec, '!');
- if(cp){
- *cp++ = 0; /* restored below */
- if(*cp)
- if(strcmp(cp, "*")) /* "!*" is the same as no user field */
- userp = cp; /* there is a user name */
- }
- if(userp == 0){ /* no user field - domain match only */
- for(i = 0; i < ndoms && doms[i]; i++)
- if(dommatch(doms[i], spec) == 0)
- ret = 1;
- } else {
- /* check for "!user", "*!user" or "domain!user" */
- if(usermatch(user, userp) == 0){
- if(*spec == 0 || strcmp(spec, "*") == 0)
- ret = 1;
- else if(ndoms > 0 && dommatch(doms[ndoms-1], spec) == 0)
- ret = 1;
- }
- }
- if(cp)
- cp[-1] = '!';
- return ret;
- }
- /*
- * match a user name. the only meta-char is '*' which matches all
- * characters. we only allow it as "*", which matches anything or
- * an * at the end of the name (e.g., "username*") which matches
- * trailing characters.
- */
- static int
- usermatch(char *pathuser, char *specuser)
- {
- int n;
- n = strlen(specuser)-1;
- if(specuser[n] == '*'){
- if(n == 0) /* match everything */
- return 0;
- return strncmp(pathuser, specuser, n);
- }
- return strcmp(pathuser, specuser);
- }
- /*
- * Match a domain specification
- */
- static int
- dommatch(char *pathdom, char *specdom)
- {
- int n;
- if (*specdom == '*'){
- if (specdom[1] == '.' && specdom[2]){
- specdom += 2;
- n = strlen(pathdom)-strlen(specdom);
- if(n == 0 || (n > 0 && pathdom[n-1] == '.'))
- return strcmp(pathdom+n, specdom);
- return n;
- }
- }
- return strcmp(pathdom, specdom);
- }
- /*
- * Custom allocators to avoid malloc overheads on small objects.
- * We never free these. (See below.)
- */
- typedef struct Stringtab Stringtab;
- struct Stringtab {
- Stringtab *link;
- char *str;
- };
- static Stringtab*
- taballoc(void)
- {
- static Stringtab *t;
- static uint nt;
- if(nt == 0){
- t = malloc(64*sizeof(Stringtab));
- if(t == 0)
- fatal("out of memory");
- nt = 64;
- }
- nt--;
- return t++;
- }
- static char*
- xstrdup(char *s)
- {
- char *r;
- int len;
- static char *t;
- static int nt;
- len = strlen(s)+1;
- if(len >= 8192)
- fatal("strdup big string");
- if(nt < len){
- t = malloc(8192);
- if(t == 0)
- fatal("out of memory");
- nt = 8192;
- }
- r = t;
- t += len;
- nt -= len;
- strcpy(r, s);
- return r;
- }
- /*
- * Return a uniquely allocated copy of a string.
- * Don't free these -- they stay in the table for the
- * next caller who wants that particular string.
- * String comparison can be done with pointer comparison
- * if you know both strings are atoms.
- */
- static Stringtab *stab[1024];
- static uint
- hash(char *s)
- {
- uint h;
- uint8_t *p;
- h = 0;
- for(p=(uint8_t*)s; *p; p++)
- h = h*37 + *p;
- return h;
- }
- char*
- atom(char *str)
- {
- uint h;
- Stringtab *tab;
-
- h = hash(str) % nelem(stab);
- for(tab=stab[h]; tab; tab=tab->link)
- if(strcmp(str, tab->str) == 0)
- return tab->str;
- tab = taballoc();
- tab->str = xstrdup(str);
- tab->link = stab[h];
- stab[h] = tab;
- return tab->str;
- }
|