lasdns.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. /* lasdns.c
  13. * This file contains the DNS LAS code.
  14. */
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <sys/types.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <netdb.h>
  22. #include <netsite.h>
  23. extern "C" {
  24. #include <prnetdb.h>
  25. }
  26. #include <base/plist.h>
  27. #include <base/pool.h>
  28. #include <libaccess/nserror.h>
  29. #include <libaccess/nsauth.h>
  30. #include <libaccess/acl.h>
  31. #include "aclpriv.h"
  32. #include <libaccess/aclproto.h>
  33. #include <libaccess/las.h>
  34. #include "lasdns.h"
  35. #include "aclutil.h"
  36. #include "aclcache.h"
  37. #include "permhash.h"
  38. #include <libaccess/dbtlibaccess.h>
  39. #include <libaccess/aclerror.h>
  40. #include "access_plhash.h"
  41. extern "C" {
  42. #include <nspr.h>
  43. }
  44. #ifdef UTEST
  45. extern int LASDnsGetDns(char **dnsv);
  46. #endif
  47. /* LASDnsMatch
  48. * Given an array of fully-qualified dns names, tries to match them
  49. * against a given hash table.
  50. * INPUT
  51. * dns DNS string
  52. * context pointer to an LAS DNS context structure
  53. *
  54. * In our usage, this context is derived from
  55. * an acllist cache, which is a representation of
  56. * of some global acis--in other words it's a global thing
  57. * shared between threads--hence the use
  58. * of the "read-only" hash lookup routines here.
  59. */
  60. int
  61. LASDnsMatch(char *token, LASDnsContext_t *context)
  62. {
  63. /* Test for the unusual case where "*" is allowed */
  64. if (ACL_HashTableLookup_const(context->Table, "*"))
  65. return LAS_EVAL_TRUE;
  66. /* Start with the full name. Then strip off each component
  67. * leaving the remainder starting with a period. E.g.
  68. * splash.mcom.com
  69. * .mcom.com
  70. * .com
  71. * Search the hash table for each remaining portion. Remember that
  72. * wildcards were put in with the leading period intact.
  73. */
  74. do {
  75. if (ACL_HashTableLookup_const(context->Table, token))
  76. return LAS_EVAL_TRUE;
  77. token = strchr(&token[1], '.');
  78. } while (token != NULL);
  79. return LAS_EVAL_FALSE;
  80. }
  81. /* LASDNSBuild
  82. * Builds a hash table of all the hostnames provided (plus their aliases
  83. * if aliasflg is true). Wildcards are only permitted in the leftmost
  84. * field. They're represented in the hash table by a leading period.
  85. * E.g. ".mcom.com".
  86. *
  87. * RETURNS Zero on success, else LAS_EVAL_INVALID
  88. */
  89. int
  90. LASDnsBuild(NSErr_t *errp, char *attr_pattern, LASDnsContext_t *context, int aliasflg)
  91. {
  92. size_t delimiter; /* length of valid tokeni */
  93. char token[256]; /* max length dns name */
  94. int i;
  95. char **p;
  96. pool_handle_t *pool;
  97. PRStatus error=PR_SUCCESS;
  98. char buffer[PR_NETDB_BUF_SIZE];
  99. #ifdef UTEST
  100. struct hostent *he, host;
  101. #else
  102. PRHostEnt *he, host;
  103. #endif
  104. char *end_attr_pattern;
  105. if (attr_pattern == NULL) {
  106. nserrGenerate(errp, ACLERRINVAL, ACLERR4770, ACL_Program, 1,
  107. XP_GetAdminStr(DBT_lasdnsbuildInvalidAttributePattern_));
  108. return LAS_EVAL_INVALID;
  109. }
  110. context->Table = PR_NewHashTable(0,
  111. PR_HashCaseString,
  112. PR_CompareCaseStrings,
  113. PR_CompareValues,
  114. &ACLPermAllocOps,
  115. NULL);
  116. pool = pool_create();
  117. context->pool = pool;
  118. if ((!context->Table) || (!context->pool)) {
  119. nserrGenerate(errp, ACLERRNOMEM, ACLERR4700, ACL_Program, 1,
  120. XP_GetAdminStr(DBT_lasdnsbuildUnableToAllocateHashT_));
  121. return LAS_EVAL_INVALID;
  122. }
  123. end_attr_pattern = attr_pattern + strlen(attr_pattern);
  124. do {
  125. size_t maxsize = sizeof(token);
  126. /* Get a single hostname from the pattern string */
  127. delimiter = strcspn(attr_pattern, ", \t");
  128. if (delimiter >= maxsize) {
  129. delimiter = maxsize-1;
  130. }
  131. PL_strncpyz(token, attr_pattern, delimiter + 1);
  132. token[delimiter] = '\0';
  133. /* Skip any white space after the token */
  134. attr_pattern += delimiter;
  135. if (attr_pattern < end_attr_pattern) {
  136. attr_pattern += strspn(attr_pattern, ", \t");
  137. }
  138. /* If there's a wildcard, strip it off but leave the "."
  139. * Can't have aliases for a wildcard pattern.
  140. * Treat "*" as a special case. If so, go ahead and hash it.
  141. */
  142. if (token[0] == '*') {
  143. if (token[1] != '\0') {
  144. if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[1]), (void *)-1)) {
  145. nserrGenerate(errp, ACLERRFAIL, ACLERR4710, ACL_Program, 2,
  146. XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
  147. return LAS_EVAL_INVALID;
  148. }
  149. } else {
  150. if (!PR_HashTableAdd(context->Table, pool_strdup(pool, token), (void *)-1)) {
  151. nserrGenerate(errp, ACLERRFAIL, ACLERR4720, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
  152. return LAS_EVAL_INVALID;
  153. }
  154. }
  155. } else {
  156. /* This is a single hostname add it to the hash table */
  157. if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[0]), (void *)-1)) {
  158. nserrGenerate(errp, ACLERRFAIL, ACLERR4730, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
  159. return LAS_EVAL_INVALID;
  160. }
  161. if (aliasflg) {
  162. void *iter = NULL;
  163. int addrcnt = 0;
  164. PRNetAddr *netaddr = (PRNetAddr *)PERM_CALLOC(sizeof(PRNetAddr));
  165. PRAddrInfo *infop = PR_GetAddrInfoByName(token,
  166. PR_AF_UNSPEC, (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME));
  167. if (!netaddr) {
  168. if (infop) {
  169. PR_FreeAddrInfo(infop);
  170. }
  171. return LAS_EVAL_NEED_MORE_INFO; /* hostname not known to dns? */
  172. }
  173. if (!infop) {
  174. if (netaddr) {
  175. PERM_FREE(netaddr);
  176. }
  177. return LAS_EVAL_NEED_MORE_INFO; /* hostname not known to dns? */
  178. }
  179. /* need to count the address, first */
  180. while ((iter = PR_EnumerateAddrInfo(iter, infop, 0, netaddr))) {
  181. addrcnt++;
  182. }
  183. if (0 == addrcnt) {
  184. PERM_FREE(netaddr);
  185. PR_FreeAddrInfo(infop);
  186. return LAS_EVAL_NEED_MORE_INFO; /* hostname not known to dns? */
  187. }
  188. iter = NULL; /* from the beginning */
  189. memset(netaddr, 0, sizeof(PRNetAddr));
  190. for (i = 0; i < addrcnt; i++) {
  191. iter = PR_EnumerateAddrInfo( iter, infop, 0, netaddr );
  192. if (NULL == iter) {
  193. break;
  194. }
  195. error = PR_GetHostByAddr(netaddr, buffer,
  196. PR_NETDB_BUF_SIZE, &host);
  197. if (error == PR_SUCCESS) {
  198. he = &host;
  199. } else {
  200. continue;
  201. }
  202. if (he->h_name) {
  203. /* Add it to the hash table */
  204. if (!PR_HashTableAdd(context->Table,
  205. pool_strdup(pool, he->h_name),
  206. (void *)-1)) {
  207. nserrGenerate(errp, ACLERRFAIL, ACLERR4750,
  208. ACL_Program, 2,
  209. XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_),
  210. he->h_name);
  211. PERM_FREE(netaddr);
  212. PR_FreeAddrInfo(infop);
  213. return LAS_EVAL_INVALID;
  214. }
  215. }
  216. if (he->h_aliases && he->h_aliases[0]) {
  217. for (p = he->h_aliases; *p; ++p) {
  218. /* Add it to the hash table */
  219. if (!PR_HashTableAdd(context->Table,
  220. pool_strdup(pool, *p),
  221. (void *)-1)) {
  222. nserrGenerate(errp, ACLERRFAIL, ACLERR4760,
  223. ACL_Program, 2,
  224. XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_),
  225. *p);
  226. PERM_FREE(netaddr);
  227. PR_FreeAddrInfo(infop);
  228. return LAS_EVAL_INVALID;
  229. }
  230. }
  231. }
  232. } /* for (i = 0; i < addrcnt; i++) */
  233. PERM_FREE(netaddr);
  234. PR_FreeAddrInfo(infop);
  235. } /* if aliasflg */
  236. } /* else - single hostname */
  237. } while ((attr_pattern != NULL) &&
  238. (attr_pattern[0] != '\0') &&
  239. (delimiter != 0));
  240. return 0;
  241. }
  242. /* LASDnsFlush
  243. * Given the address of a las_cookie for a DNS expression entry, frees up
  244. * all allocated memory for it. This includes the hash table, plus the
  245. * context structure.
  246. */
  247. void
  248. LASDnsFlush(void **las_cookie)
  249. {
  250. if (*las_cookie == NULL)
  251. return;
  252. pool_destroy(((LASDnsContext_t *)*las_cookie)->pool);
  253. PR_HashTableDestroy(((LASDnsContext_t *)*las_cookie)->Table);
  254. PERM_FREE(*las_cookie);
  255. *las_cookie = NULL;
  256. return;
  257. }
  258. /*
  259. * LASDnsEval
  260. * INPUT
  261. * attr_name The string "dns" - in lower case.
  262. * comparator CMP_OP_EQ or CMP_OP_NE only
  263. * attr_pattern A comma-separated list of DNS names
  264. * Any segment(s) in a DNS name can be wildcarded using
  265. * "*". Note that this is not a true Regular Expression
  266. * form.
  267. * *cachable Always set to ACL_INDEF_CACHE
  268. * subject Subject property list
  269. * resource Resource property list
  270. * auth_info Authentication info, if any
  271. * RETURNS
  272. * ret code The usual LAS return codes.
  273. */
  274. int LASDnsEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  275. char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
  276. PList_t subject, PList_t resource,
  277. PList_t auth_info, PList_t global_auth)
  278. {
  279. int result;
  280. int aliasflg;
  281. char *my_dns;
  282. LASDnsContext_t *context = NULL;
  283. int rv;
  284. *cachable = ACL_INDEF_CACHABLE;
  285. if (strcmp(attr_name, "dns") == 0) {
  286. /* Enable aliasflg for "dns", which allows "dns" hostname to look up
  287. * DSN hash table using the primary hostname. */
  288. aliasflg = 1;
  289. } else if (strcmp(attr_name, "dnsalias") == 0) {
  290. aliasflg = 1;
  291. } else {
  292. nserrGenerate(errp, ACLERRINVAL, ACLERR4800, ACL_Program, 2, XP_GetAdminStr(DBT_lasDnsBuildReceivedRequestForAtt_), attr_name);
  293. return LAS_EVAL_INVALID;
  294. }
  295. if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
  296. nserrGenerate(errp, ACLERRINVAL, ACLERR4810, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalIllegalComparatorDN_), comparator_string(comparator));
  297. return LAS_EVAL_INVALID;
  298. }
  299. /* If this is the first time through, build the pattern tree first. */
  300. if (*LAS_cookie == NULL) {
  301. ACL_CritEnter();
  302. if (*LAS_cookie == NULL) { /* Must check again */
  303. *LAS_cookie = context =
  304. (LASDnsContext_t *)PERM_MALLOC(sizeof(LASDnsContext_t));
  305. if (context == NULL) {
  306. nserrGenerate(errp, ACLERRNOMEM, ACLERR4820, ACL_Program, 1, XP_GetAdminStr(DBT_lasdnsevalUnableToAllocateContex_));
  307. ACL_CritExit();
  308. return LAS_EVAL_FAIL;
  309. }
  310. context->Table = NULL;
  311. if (LASDnsBuild(errp, attr_pattern, context, aliasflg) ==
  312. LAS_EVAL_INVALID) {
  313. /* Error is already printed in LASDnsBuild */
  314. ACL_CritExit();
  315. return LAS_EVAL_FAIL;
  316. }
  317. /* After this line, it is assured context->Table is not NULL. */
  318. } else {
  319. context = (LASDnsContext *) *LAS_cookie;
  320. }
  321. ACL_CritExit();
  322. } else {
  323. ACL_CritEnter();
  324. context = (LASDnsContext *) *LAS_cookie;
  325. ACL_CritExit();
  326. }
  327. /* Call the DNS attribute getter */
  328. #ifdef UTEST
  329. LASDnsGetDns(&my_dns); /* gets stuffed on return */
  330. #else
  331. rv = ACL_GetAttribute(errp, ACL_ATTR_DNS, (void **)&my_dns,
  332. subject, resource, auth_info, global_auth);
  333. if (rv != LAS_EVAL_TRUE) {
  334. if (subject || resource) {
  335. char rv_str[16];
  336. /* Don't ereport if called from ACL_CachableAclList */
  337. sprintf(rv_str, "%d", rv);
  338. nserrGenerate(errp, ACLERRINVAL, ACLERR4830, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalUnableToGetDnsErrorDN_), rv_str);
  339. }
  340. return LAS_EVAL_FAIL;
  341. }
  342. #endif
  343. result = LASDnsMatch(my_dns, context);
  344. if (comparator == CMP_OP_NE) {
  345. if (result == LAS_EVAL_FALSE)
  346. return LAS_EVAL_TRUE;
  347. else if (result == LAS_EVAL_TRUE)
  348. return LAS_EVAL_FALSE;
  349. }
  350. return (result);
  351. }