You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

737 lines
24 KiB

  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. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /* aclip.c
  13. * This file contains the IP LAS code.
  14. */
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <netsite.h>
  18. #include <base/plist.h>
  19. #include <libaccess/nserror.h>
  20. #include <libaccess/nsauth.h>
  21. #include <libaccess/acl.h>
  22. #include "aclpriv.h"
  23. #include <libaccess/aclproto.h>
  24. #include <libaccess/las.h>
  25. #include "lasip.h"
  26. #include "aclutil.h"
  27. #include "aclcache.h"
  28. #include <libaccess/dbtlibaccess.h>
  29. #include <libaccess/aclerror.h>
  30. #include <prio.h>
  31. #include "nspr.h"
  32. #define LAS_IP_IS_CONSTANT(x) (((x) == (LASIpTree_t *)LAS_EVAL_TRUE) || ((x) == (LASIpTree_t *)LAS_EVAL_FALSE))
  33. #ifdef UTEST
  34. extern int LASIpGetIp();
  35. #endif
  36. static int colonhex_ipv6(char *ipstr, const char *netmaskstr, PRIPv6Addr *ipv6, int *netmask);
  37. static int LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop);
  38. static int LASIpAddPatternIPv6(NSErr_t *errp, int netmask, PRIPv6Addr *ipv6, LASIpTree_t **treetop);
  39. /* dotdecimal
  40. * Takes netmask and ip strings and returns the numeric values,
  41. * accounting for wildards in the ip specification. Wildcards in the
  42. * ip override the netmask where they conflict.
  43. * INPUT
  44. * ipstr e.g. "123.45.67.89"
  45. * netmaskstr e.g. "255.255.255.0"
  46. * RETURNS
  47. * *ip
  48. * *netmask e.g. 0xffffff00
  49. * result NULL on success or else one of the LAS_EVAL_* codes.
  50. */
  51. int
  52. dotdecimal(char *ipstr, const char *netmaskstr, int *ip, int *netmask)
  53. {
  54. int i;
  55. char token[64];
  56. char *dotptr; /* location of the "." */
  57. int dotidx; /* index of the period char */
  58. /* Sanity check the patterns */
  59. /* Netmask can only have digits and periods. */
  60. if (strcspn(netmaskstr, "0123456789."))
  61. return LAS_EVAL_INVALID;
  62. /* IP can only have digits, periods and "*" */
  63. if (strcspn(ipstr, "0123456789.*")) {
  64. return LAS_EVAL_INVALID;
  65. }
  66. if (strlen(netmaskstr) >= sizeof(token)) {
  67. return LAS_EVAL_INVALID;
  68. }
  69. if (strlen(ipstr) >= sizeof(token)) {
  70. return LAS_EVAL_INVALID;
  71. }
  72. *netmask = *ip = 0; /* Start with "don't care" */
  73. for (i=0; i<4; i++) {
  74. dotptr = strchr((char*)netmaskstr, '.');
  75. /* copy out the token, then point beyond it */
  76. if (dotptr == NULL)
  77. strcpy(token, netmaskstr);
  78. else {
  79. dotidx = dotptr-netmaskstr;
  80. strncpy(token, netmaskstr, dotidx);
  81. token[dotidx] = '\0';
  82. netmaskstr = ++dotptr; /* skip the period */
  83. }
  84. /* Turn into a number and shift left as appropriate */
  85. *netmask += (atoi(token))<<(8*(4-i-1));
  86. if (dotptr == NULL)
  87. break;
  88. }
  89. for (i=0; i<4; i++) {
  90. dotptr = strchr(ipstr, '.');
  91. /* copy out the token, then point beyond it */
  92. if (dotptr == NULL)
  93. strcpy(token, ipstr);
  94. else {
  95. dotidx = dotptr-ipstr;
  96. strncpy(token, ipstr, dotidx);
  97. token[dotidx] = '\0';
  98. ipstr = ++dotptr;
  99. }
  100. /* check for wildcard */
  101. if (strcmp(token, "*") == 0) {
  102. switch(i) {
  103. case 0:
  104. if (dotptr == NULL)
  105. *netmask &= 0x00000000;
  106. else
  107. *netmask &= 0x00ffffff;
  108. break;
  109. case 1:
  110. if (dotptr == NULL)
  111. *netmask &= 0xff000000;
  112. else
  113. *netmask &= 0xff00ffff;
  114. break;
  115. case 2:
  116. if (dotptr == NULL)
  117. *netmask &= 0xffff0000;
  118. else
  119. *netmask &= 0xffff00ff;
  120. break;
  121. case 3:
  122. *netmask &= 0xffffff00;
  123. break;
  124. }
  125. continue;
  126. } else {
  127. /* Turn into a number and shift left as appropriate */
  128. *ip += (atoi(token))<<(8*(4-i-1));
  129. }
  130. /* check for end of string */
  131. if (dotptr == NULL) {
  132. switch(i) {
  133. case 0:
  134. *netmask &= 0xff000000;
  135. break;
  136. case 1:
  137. *netmask &= 0xffff0000;
  138. break;
  139. case 2:
  140. *netmask &= 0xffffff00;
  141. break;
  142. }
  143. break;
  144. }
  145. }
  146. return 0;
  147. }
  148. /* LASIpTreeAlloc
  149. * Malloc a node and set the actions to LAS_EVAL_FALSE
  150. */
  151. static LASIpTree_t *
  152. LASIpTreeAllocNode(NSErr_t *errp)
  153. {
  154. LASIpTree_t *newnode;
  155. newnode = (LASIpTree_t *)PERM_MALLOC(sizeof(LASIpTree_t));
  156. if (newnode == NULL) {
  157. nserrGenerate(errp, ACLERRNOMEM, ACLERR5000, ACL_Program, 1, XP_GetAdminStr(DBT_lasiptreeallocNoMemoryN_));
  158. return NULL;
  159. }
  160. newnode->action[0] = (LASIpTree_t *)LAS_EVAL_FALSE;
  161. newnode->action[1] = (LASIpTree_t *)LAS_EVAL_FALSE;
  162. return newnode;
  163. }
  164. /* LASIpTreeDealloc
  165. * Deallocates a Tree starting from a given node down.
  166. * INPUT
  167. * startnode Starting node to remove. Could be a constant in
  168. * which case, just return success.
  169. * OUTPUT
  170. * N/A
  171. */
  172. static void
  173. LASIpTreeDealloc(LASIpTree_t *startnode)
  174. {
  175. int i;
  176. if (startnode == NULL)
  177. return;
  178. /* If this is just a constant then we're done */
  179. if (LAS_IP_IS_CONSTANT(startnode))
  180. return;
  181. /* Else recursively call ourself for each branch down */
  182. for (i=0; i<2; i++) {
  183. if (!(LAS_IP_IS_CONSTANT(startnode->action[i])))
  184. LASIpTreeDealloc(startnode->action[i]);
  185. }
  186. /* Now deallocate the local node */
  187. PERM_FREE(startnode);
  188. }
  189. /*
  190. * LASIpBuild
  191. * INPUT
  192. * attr_name The string "ip" - in lower case.
  193. * comparator CmpOpEQ or CmpOpNE only
  194. * attr_pattern A comma-separated list of IP addresses and netmasks
  195. * in dotted-decimal form. Netmasks are optionally
  196. * prepended to the IP address using a plus sign. E.g.
  197. * 255.255.255.0+123.45.67.89. Any byte in the IP address
  198. * (but not the netmask) can be wildcarded using "*"
  199. * context A pointer to the IP LAS context structure.
  200. * RETURNS
  201. * ret code The usual LAS return codes.
  202. */
  203. static int
  204. LASIpBuild(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, LASIpContext_t *context)
  205. {
  206. unsigned int delimiter; /* length of valid token */
  207. char token[64], token2[64]; /* a single ip[+netmask] */
  208. char *curptr; /* current place in attr_pattern */
  209. int netmask = 0;
  210. int ip = 0;
  211. char *plusptr;
  212. int retcode;
  213. if (NULL == context) {
  214. return ACL_RES_ERROR;
  215. }
  216. /*
  217. * IP address can be delimited by space, tab, comma, or carriage return only.
  218. */
  219. curptr = attr_pattern;
  220. do {
  221. delimiter = strcspn(curptr, ", \t");
  222. delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
  223. strncpy(token, curptr, delimiter);
  224. if (delimiter >= sizeof(token)) {
  225. return LAS_EVAL_INVALID;
  226. }
  227. token[delimiter] = '\0';
  228. /* skip all the white space after the token */
  229. curptr = strpbrk((curptr+delimiter), "1234567890+.*ABCDEFabcdef:/");
  230. /*
  231. * IPv4 addresses do not have ":"
  232. */
  233. if( strstr(token,":") == NULL ){
  234. /* Is there a netmask? */
  235. plusptr = strchr(token, '+');
  236. if (plusptr == NULL) {
  237. if (curptr && (*curptr == '+')) {
  238. /* There was a space before (and possibly after) the plus sign*/
  239. curptr = strpbrk((++curptr), "1234567890.*");
  240. delimiter = strcspn(curptr, ", \t");
  241. delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
  242. if (delimiter >= sizeof(token2)) {
  243. return LAS_EVAL_INVALID;
  244. }
  245. strncpy(token2, curptr, delimiter);
  246. token2[delimiter] = '\0';
  247. retcode = dotdecimal(token, token2, &ip, &netmask);
  248. if (retcode)
  249. return (retcode);
  250. curptr = strpbrk((++curptr), "1234567890+.*");
  251. } else {
  252. retcode = dotdecimal(token, "255.255.255.255", &ip, &netmask);
  253. if (retcode)
  254. return (retcode);
  255. }
  256. } else {
  257. /* token is the IP addr string in both cases */
  258. *plusptr ='\0'; /* truncate the string */
  259. retcode =dotdecimal(token, ++plusptr, &ip, &netmask);
  260. if (retcode)
  261. return (retcode);
  262. }
  263. if (LASIpAddPattern(errp, netmask, ip, &context->treetop) != 0)
  264. return LAS_EVAL_INVALID;
  265. } else {
  266. /*
  267. * IPv6
  268. */
  269. PRIPv6Addr ipv6;
  270. plusptr = strchr(token, '/');
  271. if (plusptr == NULL) {
  272. if (curptr && (*curptr == '/')) {
  273. /* There was a space before (and possibly after) the plus sign */
  274. curptr = strpbrk((++curptr), "1234567890.*:ABCDEFabcdef");
  275. delimiter = strcspn(curptr, ", \t");
  276. delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
  277. strncpy(token2, curptr, delimiter);
  278. token2[delimiter] = '\0';
  279. retcode = colonhex_ipv6(token, token2, &ipv6, &netmask);
  280. if (retcode)
  281. return (retcode);
  282. curptr = strpbrk((++curptr), "1234567890+.:ABCDEFabcdef*");
  283. } else {
  284. retcode = colonhex_ipv6(token, "128", &ipv6, &netmask);
  285. if (retcode)
  286. return (retcode);
  287. }
  288. } else {
  289. /* token is the IP addr string in both cases */
  290. *plusptr ='\0'; /* truncate the string */
  291. retcode = colonhex_ipv6(token, ++plusptr, &ipv6, &netmask);
  292. if (retcode)
  293. return (retcode);
  294. }
  295. if (LASIpAddPatternIPv6(errp, netmask, &ipv6, &context->treetop_ipv6) != 0) {
  296. return LAS_EVAL_INVALID;
  297. }
  298. }
  299. } while ((curptr != NULL) && (delimiter != 0));
  300. return 0;
  301. }
  302. /* LASIpAddPattern
  303. * Takes a netmask and IP address and a pointer to an existing IP
  304. * tree and adds nodes as appropriate to recognize the new pattern.
  305. * INPUT
  306. * netmask e.g. 0xffffff00
  307. * pattern IP address in 4 bytes
  308. * *treetop An existing IP tree or 0 if a new tree
  309. * RETURNS
  310. * ret code NULL on success, ACL_RES_ERROR on failure
  311. * **treetop If this is a new tree, the head of the tree.
  312. */
  313. static int
  314. LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
  315. {
  316. int stopbit; /* Don't care after this point */
  317. int curbit; /* current bit we're working on */
  318. int curval; /* value of pattern[curbit] */
  319. LASIpTree_t *curptr = NULL; /* pointer to the current node */
  320. LASIpTree_t *newptr;
  321. if (NULL == treetop) {
  322. return ACL_RES_ERROR;
  323. }
  324. /* stop at the first 1 in the netmask from low to high */
  325. for (stopbit=0; stopbit<32; stopbit++) {
  326. if ((netmask&(1<<stopbit)) != 0)
  327. break;
  328. }
  329. /* Special case if there's no tree. Allocate the first node */
  330. if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
  331. curptr = LASIpTreeAllocNode(errp);
  332. if (curptr == NULL) {
  333. nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1,
  334. XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
  335. return ACL_RES_ERROR;
  336. }
  337. *treetop = curptr;
  338. }
  339. /*
  340. * Special case if the netmask is 0.
  341. */
  342. if (stopbit > 31) {
  343. (*treetop)->action[0] = (LASIpTree_t *)LAS_EVAL_TRUE;
  344. (*treetop)->action[1] = (LASIpTree_t *)LAS_EVAL_TRUE;
  345. return 0;
  346. }
  347. /* follow the tree down the pattern path bit by bit until the
  348. * end of the tree is reached (i.e. a constant).
  349. */
  350. for (curbit=31,curptr=*treetop; curbit >= 0; curbit--) {
  351. /* Is the current bit ON? If so set curval to 1 else 0 */
  352. curval = (pattern & (1<<curbit)) ? 1 : 0;
  353. /* Are we done, if so remove the rest of the tree */
  354. if (curbit == stopbit) {
  355. LASIpTreeDealloc(curptr->action[curval]);
  356. curptr->action[curval] = (LASIpTree_t *)LAS_EVAL_TRUE;
  357. /* This is the normal exit point. Most other exits must be due to errors. */
  358. return 0;
  359. }
  360. /* Oops reached the end - must allocate */
  361. if (LAS_IP_IS_CONSTANT(curptr->action[curval])) {
  362. newptr = LASIpTreeAllocNode(errp);
  363. if (newptr == NULL) {
  364. LASIpTreeDealloc(*treetop);
  365. nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1,
  366. XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
  367. return ACL_RES_ERROR;
  368. }
  369. curptr->action[curval] = newptr;
  370. }
  371. /* Keep going down the tree */
  372. curptr = curptr->action[curval];
  373. }
  374. return ACL_RES_ERROR;
  375. }
  376. /* LASIpFlush
  377. * Deallocates any memory previously allocated by the LAS
  378. */
  379. void
  380. LASIpFlush(void **las_cookie)
  381. {
  382. if (*las_cookie == NULL)
  383. return;
  384. LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop);
  385. LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop_ipv6);
  386. PERM_FREE(*las_cookie);
  387. *las_cookie = NULL;
  388. return;
  389. }
  390. /*
  391. * LASIpEval
  392. * INPUT
  393. * attr_name The string "ip" - in lower case.
  394. * comparator CMP_OP_EQ or CMP_OP_NE only
  395. * attr_pattern A comma-separated list of IP addresses and netmasks
  396. * in dotted-decimal form. Netmasks are optionally
  397. * prepended to the IP address using a plus sign. E.g.
  398. * 255.255.255.0+123.45.67.89. Any byte in the IP address
  399. * (but not the netmask) can be wildcarded using "*"
  400. * *cachable Always set to ACL_INDEF_CACHABLE
  401. * subject Subject property list
  402. * resource Resource property list
  403. * auth_info The authentication info if any
  404. * RETURNS
  405. * ret code The usual LAS return codes.
  406. */
  407. int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  408. char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
  409. PList_t subject, PList_t resource, PList_t auth_info,
  410. PList_t global_auth)
  411. {
  412. LASIpContext_t *context = NULL;
  413. LASIpTree_t *node = NULL;
  414. IPAddr_t ip;
  415. PRNetAddr *client_addr = NULL;
  416. struct in_addr client_inaddr;
  417. char ip_str[124];
  418. int retcode;
  419. int value;
  420. int bit;
  421. int rc = LAS_EVAL_INVALID;
  422. int rv;
  423. *cachable = ACL_INDEF_CACHABLE;
  424. if (strcmp(attr_name, "ip") != 0) {
  425. nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2,
  426. XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name);
  427. return LAS_EVAL_INVALID;
  428. }
  429. if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
  430. nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2,
  431. XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator));
  432. return LAS_EVAL_INVALID;
  433. }
  434. /*
  435. * Get the IP addr from the session context, and store it in "client_addr
  436. */
  437. #ifndef UTEST
  438. rv = ACL_GetAttribute(errp, ACL_ATTR_IP, (void **)&client_addr, subject, resource, auth_info, global_auth);
  439. if (rv != LAS_EVAL_TRUE) {
  440. if (subject || resource) {
  441. /* Don't ereport if called from ACL_CachableAclList */
  442. char rv_str[16];
  443. sprintf(rv_str, "%d", rv);
  444. nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2,
  445. XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str);
  446. }
  447. return LAS_EVAL_FAIL;
  448. }
  449. #else
  450. ip = (IPAddr_t)LASIpGetIp();
  451. #endif
  452. /*
  453. * If this is the first time through, build the pattern tree first.
  454. */
  455. if (*LAS_cookie == NULL) {
  456. if (strcspn(attr_pattern, "0123456789.*,+ \tABCDEFabcdef:/")) {
  457. return LAS_EVAL_INVALID;
  458. }
  459. ACL_CritEnter();
  460. if (*LAS_cookie == NULL) { /* must check again */
  461. *LAS_cookie = context =
  462. (LASIpContext_t *)PERM_MALLOC(sizeof(LASIpContext_t));
  463. if (context == NULL) {
  464. nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1,
  465. XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_));
  466. ACL_CritExit();
  467. return LAS_EVAL_FAIL;
  468. }
  469. context->treetop = NULL;
  470. context->treetop_ipv6 = NULL;
  471. retcode = LASIpBuild(errp, attr_name, comparator, attr_pattern, context);
  472. if (retcode) {
  473. ACL_CritExit();
  474. return (retcode);
  475. }
  476. } else {
  477. context = (LASIpContext *) *LAS_cookie;
  478. }
  479. ACL_CritExit();
  480. } else {
  481. ACL_CritEnter();
  482. context = (LASIpContext *) *LAS_cookie;
  483. ACL_CritExit();
  484. }
  485. /*
  486. * Check if IP is ipv4/ipv6
  487. */
  488. if ( PR_IsNetAddrType( client_addr, PR_IpAddrV4Mapped) || client_addr->raw.family == PR_AF_INET ) {
  489. /*
  490. * IPv4
  491. */
  492. /* Set the appropriate s_addr for ipv4 or ipv4 mapped to ipv6 */
  493. if (client_addr->raw.family == PR_AF_INET) {
  494. client_inaddr.s_addr = client_addr->inet.ip;
  495. } else {
  496. client_inaddr.s_addr = client_addr->ipv6.ip._S6_un._S6_u32[3];
  497. }
  498. node = context->treetop;
  499. ip = (IPAddr_t)PR_ntohl( client_inaddr.s_addr );
  500. if(node == NULL){
  501. rc = (comparator == CMP_OP_EQ ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  502. } else {
  503. for (bit = 31; bit >= 0; bit--) {
  504. value = (ip & (IPAddr_t) (1 << bit)) ? 1 : 0;
  505. if (LAS_IP_IS_CONSTANT(node->action[value])){
  506. /* Reached a result, so return it */
  507. if (comparator == CMP_OP_EQ){
  508. rc = (int)(PRSize)node->action[value];
  509. break;
  510. } else {
  511. rc = ((int)(PRSize)node->action[value] == LAS_EVAL_TRUE) ? LAS_EVAL_FALSE : LAS_EVAL_TRUE;
  512. break;
  513. }
  514. } else {
  515. /* Move on to the next bit */
  516. node = node->action[value];
  517. }
  518. }
  519. }
  520. if(rc == LAS_EVAL_INVALID){
  521. sprintf(ip_str, "%x", (unsigned int)ip);
  522. nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2,
  523. XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), ip_str);
  524. }
  525. } else {
  526. /*
  527. * IPv6
  528. */
  529. PRIPv6Addr *ipv6 = &(client_addr->ipv6.ip);
  530. LASIpTree_t *node;
  531. int bit_position = 15;
  532. int field = 0;
  533. int addr = 0;
  534. int value;
  535. node = context->treetop_ipv6;
  536. if ( node == NULL ) {
  537. rc = (comparator == CMP_OP_EQ ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  538. } else {
  539. addr = PR_ntohs( ipv6->_S6_un._S6_u16[field]);
  540. for (bit = 127; bit >= 0 ; bit--, bit_position--) {
  541. value = (addr & (1 << bit_position)) ? 1 : 0;
  542. if (LAS_IP_IS_CONSTANT(node->action[value])) {
  543. /* Reached a result, so return it */
  544. if (comparator == CMP_OP_EQ){
  545. return(int)(long)node->action[value];
  546. } else {
  547. return(((int)(long)node->action[value] == LAS_EVAL_TRUE) ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  548. }
  549. } else {
  550. node = node->action[value];
  551. if ( bit % 16 == 0) {
  552. /* Ok, move to the next field in the IPv6 addr: f:f:next:f:f:f:f:f */
  553. field++;
  554. addr = PR_ntohs( ipv6->_S6_un._S6_u16[field]);
  555. bit_position = 15;
  556. }
  557. }
  558. }
  559. rc = LAS_EVAL_INVALID;
  560. }
  561. }
  562. return rc;
  563. }
  564. /*
  565. * The ipv6 version of LASIpAddPattern
  566. */
  567. static int
  568. LASIpAddPatternIPv6(NSErr_t *errp, int netmask, PRIPv6Addr *ipv6, LASIpTree_t **treetop)
  569. {
  570. LASIpTree_t *curptr;
  571. LASIpTree_t *newptr;
  572. int stopbit;
  573. int curbit;
  574. int curval;
  575. int field = 0; /* (8) 16 bit fields in a IPv6 address: x:x:x:x:x:x:x:x */
  576. int addr = 0;
  577. int curbit_position = 15; /* 16 bits: 0-15 */
  578. /* stop at the first 1 in the netmask from low to high */
  579. stopbit = 128 - netmask;
  580. /* Special case if there's no tree. Allocate the first node */
  581. if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
  582. curptr = LASIpTreeAllocNode(errp);
  583. if (curptr == NULL) {
  584. nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1,
  585. XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
  586. return ACL_RES_ERROR;
  587. }
  588. *treetop = curptr;
  589. }
  590. addr = PR_ntohs(ipv6->_S6_un._S6_u16[field]);
  591. for (curbit = 127, curptr = *treetop; curbit >= 0; curbit--, curbit_position--){
  592. /* Is the current bit ON? If so set curval to 1 else 0 */
  593. curval = (addr & (1 << curbit_position)) ? 1 : 0;
  594. /* Are we done, if so remove the rest of the tree */
  595. if (curbit == stopbit) {
  596. LASIpTreeDealloc(curptr->action[curval]);
  597. curptr->action[curval] = (LASIpTree_t *)LAS_EVAL_TRUE;
  598. /* This is the normal exit point. Most other exits must be due to errors. */
  599. return 0;
  600. }
  601. /* Oops reached the end - must allocate */
  602. if (LAS_IP_IS_CONSTANT(curptr->action[curval])) {
  603. newptr = LASIpTreeAllocNode(errp);
  604. if (newptr == NULL) {
  605. LASIpTreeDealloc(*treetop);
  606. nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1,
  607. XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
  608. return ACL_RES_ERROR;
  609. }
  610. curptr->action[curval] = newptr;
  611. }
  612. /* Keep going down the tree */
  613. curptr = curptr->action[curval];
  614. if ( curbit % 16 == 0) {
  615. /* Ok, move to the next field in the addr */
  616. field++;
  617. addr = PR_ntohs(ipv6->_S6_un._S6_u16[field]);
  618. curbit_position = 15;
  619. }
  620. }
  621. return ACL_RES_ERROR;
  622. }
  623. /*
  624. * This is very similar to dotdecimal(), but for ipv6 addresses
  625. */
  626. static int
  627. colonhex_ipv6(char *ipstr, const char *netmaskstr, PRIPv6Addr *ipv6, int *netmask)
  628. {
  629. PRNetAddr addr;
  630. /*
  631. * Validate netmaskstr - can only be digits
  632. */
  633. if (strcspn(netmaskstr, "0123456789")){
  634. return LAS_EVAL_INVALID;
  635. }
  636. /*
  637. * Validate ipstr - can only have digits, colons, hex chars, and dots
  638. */
  639. if(strcspn(ipstr, "0123456789:ABCDEFabcdef.")){
  640. return LAS_EVAL_INVALID;
  641. }
  642. /*
  643. * validate the netmask - must be between 1 and 128
  644. */
  645. *netmask = atoi(netmaskstr);
  646. if(*netmask < 1 || *netmask > 128){
  647. return LAS_EVAL_INVALID;
  648. }
  649. /*
  650. * Get the net addr
  651. */
  652. if (PR_StringToNetAddr(ipstr, &addr) != PR_SUCCESS){
  653. return LAS_EVAL_INVALID;
  654. }
  655. /*
  656. * Set the ipv6 addr
  657. */
  658. *ipv6 = addr.ipv6.ip;
  659. return 0;
  660. }