lasip.cpp 18 KB

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