lasip.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /* aclip.c
  7. * This file contains the IP LAS code.
  8. */
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <netsite.h>
  12. #include <base/plist.h>
  13. #include <libaccess/nserror.h>
  14. #include <libaccess/nsauth.h>
  15. #include <libaccess/acl.h>
  16. #include "aclpriv.h"
  17. #include <libaccess/aclproto.h>
  18. #include <libaccess/las.h>
  19. #include "lasip.h"
  20. #include "aclutil.h"
  21. #include "aclcache.h"
  22. #include <libaccess/dbtlibaccess.h>
  23. #include <libaccess/aclerror.h>
  24. #define LAS_IP_IS_CONSTANT(x) (((x) == (LASIpTree_t *)LAS_EVAL_TRUE) || ((x) == (LASIpTree_t *)LAS_EVAL_FALSE))
  25. #ifdef UTEST
  26. extern int LASIpGetIp();
  27. #endif
  28. static int
  29. LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop);
  30. /* dotdecimal
  31. * Takes netmask and ip strings and returns the numeric values,
  32. * accounting for wildards in the ip specification. Wildcards in the
  33. * ip override the netmask where they conflict.
  34. * INPUT
  35. * ipstr e.g. "123.45.67.89"
  36. * netmaskstr e.g. "255.255.255.0"
  37. * RETURNS
  38. * *ip
  39. * *netmask e.g. 0xffffff00
  40. * result NULL on success or else one of the LAS_EVAL_* codes.
  41. */
  42. int
  43. dotdecimal(char *ipstr, char *netmaskstr, int *ip, int *netmask)
  44. {
  45. int i;
  46. char token[64];
  47. char *dotptr; /* location of the "." */
  48. int dotidx; /* index of the period char */
  49. /* Sanity check the patterns */
  50. /* Netmask can only have digits and periods. */
  51. if (strcspn(netmaskstr, "0123456789."))
  52. return LAS_EVAL_INVALID;
  53. /* IP can only have digits, periods and "*" */
  54. if (strcspn(ipstr, "0123456789.*"))
  55. return LAS_EVAL_INVALID;
  56. *netmask = *ip = 0; /* Start with "don't care" */
  57. for (i=0; i<4; i++) {
  58. dotptr = strchr(netmaskstr, '.');
  59. /* copy out the token, then point beyond it */
  60. if (dotptr == NULL)
  61. strcpy(token, netmaskstr);
  62. else {
  63. dotidx = dotptr-netmaskstr;
  64. strncpy(token, netmaskstr, dotidx);
  65. token[dotidx] = '\0';
  66. netmaskstr = ++dotptr; /* skip the period */
  67. }
  68. /* Turn into a number and shift left as appropriate */
  69. *netmask += (atoi(token))<<(8*(4-i-1));
  70. if (dotptr == NULL)
  71. break;
  72. }
  73. for (i=0; i<4; i++) {
  74. dotptr = strchr(ipstr, '.');
  75. /* copy out the token, then point beyond it */
  76. if (dotptr == NULL)
  77. strcpy(token, ipstr);
  78. else {
  79. dotidx = dotptr-ipstr;
  80. strncpy(token, ipstr, dotidx);
  81. token[dotidx] = '\0';
  82. ipstr = ++dotptr;
  83. }
  84. /* check for wildcard */
  85. if (strcmp(token, "*") == 0) {
  86. switch(i) {
  87. case 0:
  88. if (dotptr == NULL)
  89. *netmask &= 0x00000000;
  90. else
  91. *netmask &= 0x00ffffff;
  92. break;
  93. case 1:
  94. if (dotptr == NULL)
  95. *netmask &= 0xff000000;
  96. else
  97. *netmask &= 0xff00ffff;
  98. break;
  99. case 2:
  100. if (dotptr == NULL)
  101. *netmask &= 0xffff0000;
  102. else
  103. *netmask &= 0xffff00ff;
  104. break;
  105. case 3:
  106. *netmask &= 0xffffff00;
  107. break;
  108. }
  109. continue;
  110. } else {
  111. /* Turn into a number and shift left as appropriate */
  112. *ip += (atoi(token))<<(8*(4-i-1));
  113. }
  114. /* check for end of string */
  115. if (dotptr == NULL) {
  116. switch(i) {
  117. case 0:
  118. *netmask &= 0xff000000;
  119. break;
  120. case 1:
  121. *netmask &= 0xffff0000;
  122. break;
  123. case 2:
  124. *netmask &= 0xffffff00;
  125. break;
  126. }
  127. break;
  128. }
  129. }
  130. return 0;
  131. }
  132. /* LASIpTreeAlloc
  133. * Malloc a node and set the actions to LAS_EVAL_FALSE
  134. */
  135. static LASIpTree_t *
  136. LASIpTreeAllocNode(NSErr_t *errp)
  137. {
  138. LASIpTree_t *newnode;
  139. newnode = (LASIpTree_t *)PERM_MALLOC(sizeof(LASIpTree_t));
  140. if (newnode == NULL) {
  141. nserrGenerate(errp, ACLERRNOMEM, ACLERR5000, ACL_Program, 1, XP_GetAdminStr(DBT_lasiptreeallocNoMemoryN_));
  142. return NULL;
  143. }
  144. newnode->action[0] = (LASIpTree_t *)LAS_EVAL_FALSE;
  145. newnode->action[1] = (LASIpTree_t *)LAS_EVAL_FALSE;
  146. return newnode;
  147. }
  148. /* LASIpTreeDealloc
  149. * Deallocates a Tree starting from a given node down.
  150. * INPUT
  151. * startnode Starting node to remove. Could be a constant in
  152. * which case, just return success.
  153. * OUTPUT
  154. * N/A
  155. */
  156. static void
  157. LASIpTreeDealloc(LASIpTree_t *startnode)
  158. {
  159. int i;
  160. if (startnode == NULL)
  161. return;
  162. /* If this is just a constant then we're done */
  163. if (LAS_IP_IS_CONSTANT(startnode))
  164. return;
  165. /* Else recursively call ourself for each branch down */
  166. for (i=0; i<2; i++) {
  167. if (!(LAS_IP_IS_CONSTANT(startnode->action[i])))
  168. LASIpTreeDealloc(startnode->action[i]);
  169. }
  170. /* Now deallocate the local node */
  171. PERM_FREE(startnode);
  172. }
  173. /*
  174. * LASIpBuild
  175. * INPUT
  176. * attr_name The string "ip" - in lower case.
  177. * comparator CmpOpEQ or CmpOpNE only
  178. * attr_pattern A comma-separated list of IP addresses and netmasks
  179. * in dotted-decimal form. Netmasks are optionally
  180. * prepended to the IP address using a plus sign. E.g.
  181. * 255.255.255.0+123.45.67.89. Any byte in the IP address
  182. * (but not the netmask) can be wildcarded using "*"
  183. * context A pointer to the IP LAS context structure.
  184. * RETURNS
  185. * ret code The usual LAS return codes.
  186. */
  187. static int
  188. LASIpBuild(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, LASIpTree_t **treetop)
  189. {
  190. unsigned int delimiter; /* length of valid token */
  191. char token[64], token2[64]; /* a single ip[+netmask] */
  192. char *curptr; /* current place in attr_pattern */
  193. int netmask, ip;
  194. char *plusptr;
  195. int retcode;
  196. /* ip address can be delimited by space, tab, comma, or carriage return
  197. * only.
  198. */
  199. curptr = attr_pattern;
  200. do {
  201. delimiter = strcspn(curptr, ", \t");
  202. delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
  203. strncpy(token, curptr, delimiter);
  204. token[delimiter] = '\0';
  205. /* skip all the white space after the token */
  206. curptr = strpbrk((curptr+delimiter), "1234567890+.*");
  207. /* Is there a netmask? */
  208. plusptr = strchr(token, '+');
  209. if (plusptr == NULL) {
  210. if (curptr && (*curptr == '+')) {
  211. /* There was a space before (and possibly after) the plus sign*/
  212. curptr = strpbrk((++curptr), "1234567890.*");
  213. delimiter = strcspn(curptr, ", \t");
  214. delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
  215. strncpy(token2, curptr, delimiter);
  216. token2[delimiter] = '\0';
  217. retcode = dotdecimal(token, token2, &ip, &netmask);
  218. if (retcode)
  219. return (retcode);
  220. curptr = strpbrk((++curptr), "1234567890+.*");
  221. } else {
  222. retcode =dotdecimal(token, "255.255.255.255", &ip, &netmask);
  223. if (retcode)
  224. return (retcode);
  225. }
  226. } else {
  227. /* token is the IP addr string in both cases */
  228. *plusptr ='\0'; /* truncate the string */
  229. retcode =dotdecimal(token, ++plusptr, &ip, &netmask);
  230. if (retcode)
  231. return (retcode);
  232. }
  233. if (LASIpAddPattern(errp, netmask, ip, treetop) != 0)
  234. return LAS_EVAL_INVALID;
  235. } while ((curptr != NULL) && (delimiter != 0));
  236. return 0;
  237. }
  238. /* LASIpAddPattern
  239. * Takes a netmask and IP address and a pointer to an existing IP
  240. * tree and adds nodes as appropriate to recognize the new pattern.
  241. * INPUT
  242. * netmask e.g. 0xffffff00
  243. * pattern IP address in 4 bytes
  244. * *treetop An existing IP tree or 0 if a new tree
  245. * RETURNS
  246. * ret code NULL on success, ACL_RES_ERROR on failure
  247. * **treetop If this is a new tree, the head of the tree.
  248. */
  249. static int
  250. LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
  251. {
  252. int stopbit; /* Don't care after this point */
  253. int curbit; /* current bit we're working on */
  254. int curval; /* value of pattern[curbit] */
  255. LASIpTree_t *curptr; /* pointer to the current node */
  256. LASIpTree_t *newptr;
  257. /* stop at the first 1 in the netmask from low to high */
  258. for (stopbit=0; stopbit<32; stopbit++) {
  259. if ((netmask&(1<<stopbit)) != 0)
  260. break;
  261. }
  262. /* Special case if there's no tree. Allocate the first node */
  263. if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
  264. curptr = LASIpTreeAllocNode(errp);
  265. if (curptr == NULL) {
  266. nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
  267. return ACL_RES_ERROR;
  268. }
  269. *treetop = curptr;
  270. }
  271. /* Special case if the netmask is 0.
  272. */
  273. if (stopbit > 31) {
  274. curptr->action[0] = (LASIpTree_t *)LAS_EVAL_TRUE;
  275. curptr->action[1] = (LASIpTree_t *)LAS_EVAL_TRUE;
  276. return 0;
  277. }
  278. /* follow the tree down the pattern path bit by bit until the
  279. * end of the tree is reached (i.e. a constant).
  280. */
  281. for (curbit=31,curptr=*treetop; curbit >= 0; curbit--) {
  282. /* Is the current bit ON? If so set curval to 1 else 0 */
  283. curval = (pattern & (1<<curbit)) ? 1 : 0;
  284. /* Are we done, if so remove the rest of the tree */
  285. if (curbit == stopbit) {
  286. LASIpTreeDealloc(curptr->action[curval]);
  287. curptr->action[curval] =
  288. (LASIpTree_t *)LAS_EVAL_TRUE;
  289. /* This is the normal exit point. Most other
  290. * exits must be due to errors.
  291. */
  292. return 0;
  293. }
  294. /* Oops reached the end - must allocate */
  295. if (LAS_IP_IS_CONSTANT(curptr->action[curval])) {
  296. newptr = LASIpTreeAllocNode(errp);
  297. if (newptr == NULL) {
  298. LASIpTreeDealloc(*treetop);
  299. nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
  300. return ACL_RES_ERROR;
  301. }
  302. curptr->action[curval] = newptr;
  303. }
  304. /* Keep going down the tree */
  305. curptr = curptr->action[curval];
  306. }
  307. return ACL_RES_ERROR;
  308. }
  309. /* LASIpFlush
  310. * Deallocates any memory previously allocated by the LAS
  311. */
  312. void
  313. LASIpFlush(void **las_cookie)
  314. {
  315. if (*las_cookie == NULL)
  316. return;
  317. LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop);
  318. PERM_FREE(*las_cookie);
  319. *las_cookie = NULL;
  320. return;
  321. }
  322. /*
  323. * LASIpEval
  324. * INPUT
  325. * attr_name The string "ip" - in lower case.
  326. * comparator CMP_OP_EQ or CMP_OP_NE only
  327. * attr_pattern A comma-separated list of IP addresses and netmasks
  328. * in dotted-decimal form. Netmasks are optionally
  329. * prepended to the IP address using a plus sign. E.g.
  330. * 255.255.255.0+123.45.67.89. Any byte in the IP address
  331. * (but not the netmask) can be wildcarded using "*"
  332. * *cachable Always set to ACL_INDEF_CACHABLE
  333. * subject Subject property list
  334. * resource Resource property list
  335. * auth_info The authentication info if any
  336. * RETURNS
  337. * ret code The usual LAS return codes.
  338. */
  339. int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  340. char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
  341. PList_t subject, PList_t resource, PList_t auth_info,
  342. PList_t global_auth)
  343. {
  344. int bit;
  345. int value;
  346. IPAddr_t ip;
  347. int retcode;
  348. LASIpTree_t *node;
  349. LASIpContext_t *context;
  350. int rv;
  351. char ip_str[124];
  352. *cachable = ACL_INDEF_CACHABLE;
  353. if (strcmp(attr_name, "ip") != 0) {
  354. nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2, XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name);
  355. return LAS_EVAL_INVALID;
  356. }
  357. if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
  358. nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator));
  359. return LAS_EVAL_INVALID;
  360. }
  361. /* GET THE IP ADDR FROM THE SESSION CONTEXT AND STORE IT IN THE
  362. * VARIABLE ip.
  363. */
  364. #ifndef UTEST
  365. rv = ACL_GetAttribute(errp, ACL_ATTR_IP, (void **)&ip,
  366. subject, resource, auth_info, global_auth);
  367. if (rv != LAS_EVAL_TRUE) {
  368. if (subject || resource) {
  369. /* Don't ereport if called from ACL_CachableAclList */
  370. char rv_str[16];
  371. sprintf(rv_str, "%d", rv);
  372. nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str);
  373. }
  374. return LAS_EVAL_FAIL;
  375. }
  376. #else
  377. ip = (IPAddr_t)LASIpGetIp();
  378. #endif
  379. /* If this is the first time through, build the pattern tree first.
  380. */
  381. if (*LAS_cookie == NULL) {
  382. if (strcspn(attr_pattern, "0123456789.*,+ \t")) {
  383. return LAS_EVAL_INVALID;
  384. }
  385. ACL_CritEnter();
  386. if (*LAS_cookie == NULL) { /* must check again */
  387. *LAS_cookie = context =
  388. (LASIpContext_t *)PERM_MALLOC(sizeof(LASIpContext_t));
  389. if (context == NULL) {
  390. nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1, XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_));
  391. ACL_CritExit();
  392. return LAS_EVAL_FAIL;
  393. }
  394. context->treetop = NULL;
  395. retcode = LASIpBuild(errp, attr_name, comparator, attr_pattern,
  396. &context->treetop);
  397. if (retcode) {
  398. ACL_CritExit();
  399. return (retcode);
  400. }
  401. }
  402. ACL_CritExit();
  403. } else
  404. context = (LASIpContext *) *LAS_cookie;
  405. node = context->treetop;
  406. for (bit=31; bit >=0; bit--) {
  407. value = (ip & (IPAddr_t) (1<<bit)) ? 1 : 0;
  408. if (LAS_IP_IS_CONSTANT(node->action[value]))
  409. /* Reached a result, so return it */
  410. if (comparator == CMP_OP_EQ)
  411. return((int)(PRSize)node->action[value]);
  412. else
  413. return(((int)(PRSize)node->action[value] ==
  414. LAS_EVAL_TRUE) ?
  415. LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  416. else
  417. /* Move on to the next bit */
  418. node = node->action[value];
  419. }
  420. /* Cannot reach here. Even a 32 bit mismatch has a conclusion in
  421. * the pattern tree.
  422. */
  423. sprintf(ip_str, "%x", ip);
  424. nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), ip_str);
  425. return LAS_EVAL_INVALID;
  426. }