ctlfiles.c 6.5 KB

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