misc.c 8.4 KB

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