lasdns.cpp 14 KB

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