ctlfiles.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "ratfs.h"
  10. #include <ip.h>
  11. enum {
  12. ACCEPT = 0, /* verbs in control file */
  13. REFUSED,
  14. DENIED,
  15. DIALUP,
  16. BLOCKED,
  17. DELAY,
  18. NONE,
  19. Subchar = '#', /* character substituted for '/' in file names */
  20. };
  21. static Keyword actions[] = {
  22. "allow", ACCEPT,
  23. "accept", ACCEPT,
  24. "block", BLOCKED,
  25. "deny", DENIED,
  26. "dial", DIALUP,
  27. "relay", DELAY,
  28. "delay", DELAY,
  29. 0, NONE,
  30. };
  31. static void acctinsert(Node*, char*);
  32. static char* getline(Biobuf*);
  33. static void ipinsert(Node*, char*);
  34. static void ipsort(void);
  35. /*
  36. * Input the configuration file
  37. * Currently we only process the "ournets"
  38. * specification.
  39. */
  40. void
  41. getconf(void)
  42. {
  43. Biobuf *bp;
  44. char *cp;
  45. Node *np, *dir, **l;
  46. if(debugfd >= 0)
  47. fprint(debugfd, "loading %s\n", conffile);
  48. bp = Bopen(conffile, OREAD);
  49. if(bp == 0)
  50. return;
  51. dir = finddir(Trusted);
  52. if(dir == 0)
  53. return;
  54. /*
  55. * if this isn't the first time, purge permanent entries
  56. */
  57. trustedqid = Qtrustedfile;
  58. if(lastconftime){
  59. l = &dir->children;
  60. for(np = dir->children; np; np = *l){
  61. if(np->d.type == Trustedperm){
  62. *l = np->sibs;
  63. free(np);
  64. } else {
  65. np->d.qid.path = trustedqid++;
  66. l = &np->sibs;
  67. }
  68. }
  69. dir->count = 0;
  70. }
  71. for(;;){
  72. cp = getline(bp);
  73. if(cp == 0)
  74. break;
  75. if (strcmp(cp, "ournets") == 0){
  76. for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){
  77. np = newnode(dir, cp, Trustedperm, 0111, trustedqid++);
  78. cidrparse(&np->ip, cp);
  79. subslash(cp);
  80. np->d.name = atom(cp);
  81. }
  82. }
  83. }
  84. Bterm(bp);
  85. lastconftime = time(0);
  86. }
  87. /*
  88. * Reload the control file, if necessary
  89. */
  90. void
  91. reload(void)
  92. {
  93. int type, action;
  94. Biobuf *bp;
  95. char *cp;
  96. Node *np, *dir;
  97. if(debugfd >= 0)
  98. fprint(debugfd,"loading %s\n", ctlfile);
  99. bp = Bopen(ctlfile, OREAD);
  100. if(bp == 0)
  101. return;
  102. if(lastctltime){
  103. for(dir = root->children; dir; dir = dir->sibs){
  104. if (dir->d.type != Addrdir)
  105. continue;
  106. for(np = dir->children; np; np = np->sibs)
  107. np->count = 0;
  108. }
  109. }
  110. for(;;){
  111. cp = getline(bp);
  112. if(cp == 0)
  113. break;
  114. type = *cp;
  115. if(type == '*'){
  116. cp++;
  117. if(*cp == 0) /* space before keyword */
  118. cp++;
  119. }
  120. action = findkey(cp, actions);
  121. if (action == NONE)
  122. continue;
  123. if (action == ACCEPT)
  124. dir = dirwalk("allow", root);
  125. else
  126. if (action == DELAY)
  127. dir = dirwalk("delay", root);
  128. else
  129. dir = dirwalk(cp, root);
  130. if(dir == 0)
  131. continue;
  132. for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){
  133. if(type == '*')
  134. acctinsert(dir, cp);
  135. else
  136. ipinsert(dir, cp);
  137. }
  138. }
  139. Bterm(bp);
  140. ipsort();
  141. dummy.d.mtime = dummy.d.atime = lastctltime = time(0);
  142. }
  143. /*
  144. * get a canonicalized line: a string of null-terminated lower-case
  145. * tokens with a two null bytes at the end.
  146. */
  147. static char*
  148. getline(Biobuf *bp)
  149. {
  150. char c, *cp, *p, *q;
  151. int n;
  152. static char *buf;
  153. static int bufsize;
  154. for(;;){
  155. cp = Brdline(bp, '\n');
  156. if(cp == 0)
  157. return 0;
  158. n = Blinelen(bp);
  159. cp[n-1] = 0;
  160. if(buf == 0 || bufsize < n+1){
  161. bufsize += 512;
  162. if(bufsize < n+1)
  163. bufsize = n+1;
  164. buf = realloc(buf, bufsize);
  165. if(buf == 0)
  166. break;
  167. }
  168. q = buf;
  169. for (p = cp; *p; p++){
  170. c = *p;
  171. if(c == '\\' && p[1]) /* we don't allow \<newline> */
  172. c = *++p;
  173. else
  174. if(c == '#')
  175. break;
  176. else
  177. if(c == ' ' || c == '\t' || c == ',')
  178. if(q == buf || q[-1] == 0)
  179. continue;
  180. else
  181. c = 0;
  182. *q++ = tolower(c);
  183. }
  184. if(q != buf){
  185. if(q[-1])
  186. *q++ = 0;
  187. *q = 0;
  188. break;
  189. }
  190. }
  191. return buf;
  192. }
  193. /*
  194. * Match a keyword
  195. */
  196. int
  197. findkey(char *val, Keyword *p)
  198. {
  199. for(; p->name; p++)
  200. if(strcmp(val, p->name) == 0)
  201. break;
  202. return p->code;
  203. }
  204. /*
  205. * parse a cidr specification in either IP/mask or IP#mask format
  206. */
  207. void
  208. cidrparse(Cidraddr *cidr, char *cp)
  209. {
  210. char *p, *slash;
  211. int c;
  212. uint32_t a, m;
  213. uint8_t addr[IPv4addrlen];
  214. uint8_t mask[IPv4addrlen];
  215. char buf[64];
  216. /*
  217. * find '/' or '#' character in the cidr specification
  218. */
  219. slash = 0;
  220. for(p = buf; p < buf+sizeof(buf)-1 && *cp; p++) {
  221. c = *cp++;
  222. switch(c) {
  223. case Subchar:
  224. c = '/';
  225. slash = p;
  226. break;
  227. case '/':
  228. slash = p;
  229. break;
  230. default:
  231. break;
  232. }
  233. *p = c;
  234. }
  235. *p = 0;
  236. v4parsecidr(addr, mask, buf);
  237. a = nhgetl(addr);
  238. m = nhgetl(mask);
  239. /*
  240. * if a mask isn't specified, we build a minimal mask
  241. * instead of using the default mask for that net. in this
  242. * case we never allow a class A mask (0xff000000).
  243. */
  244. if(slash == 0){
  245. m = 0xff000000;
  246. p = buf;
  247. for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.'))
  248. m = (m>>8)|0xff000000;
  249. /* force at least a class B */
  250. m |= 0xffff0000;
  251. }
  252. cidr->ipaddr = a;
  253. cidr->mask = m;
  254. }
  255. /*
  256. * Substitute Subchar ('#') for '/'
  257. */
  258. char*
  259. subslash(char *os)
  260. {
  261. char *s;
  262. for(s=os; *s; s++)
  263. if(*s == '/')
  264. *s = Subchar;
  265. return os;
  266. }
  267. /*
  268. * Insert an account pseudo-file in a directory
  269. */
  270. static void
  271. acctinsert(Node *np, char *cp)
  272. {
  273. int i;
  274. char *tmp;
  275. Address *ap;
  276. static char *dangerous[] = { "*", "!", "*!", "!*", "*!*", 0 };
  277. if(cp == 0 || *cp == 0)
  278. return;
  279. /* rule out dangerous patterns */
  280. for (i = 0; dangerous[i]; i++)
  281. if(strcmp(cp, dangerous[i])== 0)
  282. return;
  283. np = dirwalk("account", np);
  284. if(np == 0)
  285. return;
  286. i = np->count++;
  287. if(i >= np->allocated){
  288. np->allocated = np->count;
  289. np->addrs = realloc(np->addrs, np->allocated*sizeof(Address));
  290. if(np->addrs == 0)
  291. fatal("out of memory");
  292. }
  293. ap = &np->addrs[i]; /* new entry on end */
  294. tmp = strdup(cp);
  295. if(tmp == nil)
  296. fatal("out of memory");
  297. subslash(tmp);
  298. ap->name = atom(tmp);
  299. free(tmp);
  300. }
  301. /*
  302. * Insert an IP address pseudo-file in a directory
  303. */
  304. static void
  305. ipinsert(Node *np, char *cp)
  306. {
  307. char *tmp;
  308. int i;
  309. Address *ap;
  310. if(cp == 0 || *cp == 0)
  311. return;
  312. np = dirwalk("ip", np);
  313. if(np == 0)
  314. return;
  315. i = np->count++;
  316. if(i >= np->allocated){
  317. np->allocated = np->count;
  318. np->addrs = realloc(np->addrs, np->allocated*sizeof(Address));
  319. if(np->addrs == 0)
  320. fatal("out of memory");
  321. }
  322. ap = &np->addrs[i]; /* new entry on end */
  323. tmp = strdup(cp);
  324. if(tmp == nil)
  325. fatal("out of memory");
  326. subslash(tmp);
  327. ap->name = atom(tmp);
  328. free(tmp);
  329. cidrparse(&ap->ip, cp);
  330. }
  331. int
  332. ipcomp(const void *a, const void *b)
  333. {
  334. uint32_t aip, bip;
  335. aip = ((Address*)a)->ip.ipaddr;
  336. bip = ((Address*)b)->ip.ipaddr;
  337. if(aip > bip)
  338. return 1;
  339. if(aip < bip)
  340. return -1;
  341. return 0;
  342. }
  343. /*
  344. * Sort a directory of IP addresses
  345. */
  346. static void
  347. ipsort(void)
  348. {
  349. int base;
  350. Node *dir, *np;
  351. base = Qaddrfile;
  352. for(dir = root->children; dir; dir = dir->sibs){
  353. if (dir->d.type != Addrdir)
  354. continue;
  355. for(np = dir->children; np; np = np->sibs){
  356. if(np->d.type == IPaddr && np->count && np->addrs)
  357. qsort(np->addrs, np->count, sizeof(Address), ipcomp);
  358. np->baseqid = base;
  359. base += np->count;
  360. }
  361. }
  362. }