diff options
Diffstat (limited to 'lib/libaccess/lasdns.cpp')
-rw-r--r-- | lib/libaccess/lasdns.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/lib/libaccess/lasdns.cpp b/lib/libaccess/lasdns.cpp new file mode 100644 index 00000000..22a37dac --- /dev/null +++ b/lib/libaccess/lasdns.cpp @@ -0,0 +1,373 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +/* lasdns.c + * This file contains the DNS LAS code. + */ + +#include <stdio.h> +#include <string.h> + +#ifdef XP_WIN32 +/* #include <winsock2.h> */ +#include <winsock.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#endif + +#include <netsite.h> +extern "C" { +#include <prnetdb.h> +} +#include <base/plist.h> +#include <base/pool.h> +#include <libaccess/nserror.h> +#include <libaccess/nsauth.h> +#include <libaccess/acl.h> +#include "aclpriv.h" +#include <libaccess/aclproto.h> +#include <libaccess/las.h> +#include "lasdns.h" +#include "aclutil.h" +#include "aclcache.h" +#include "permhash.h" +#include <libaccess/dbtlibaccess.h> +#include <libaccess/aclerror.h> +#include "access_plhash.h" +extern "C" { +#include <nspr.h> +} + +#ifdef UTEST +extern int LASDnsGetDns(char **dnsv); +#endif + +/* LASDnsMatch + * Given an array of fully-qualified dns names, tries to match them + * against a given hash table. + * INPUT + * dns DNS string + * context pointer to an LAS DNS context structure + * + * In our usage, this context is derived from + * an acllist cache, which is a representation of + * of some global acis--in other words it's a global thing + * shared between threads--hence the use + * of the "read-only" hash lookup routines here. + */ +int +LASDnsMatch(char *token, LASDnsContext_t *context) +{ + + /* Test for the unusual case where "*" is allowed */ + if (ACL_HashTableLookup_const(context->Table, "*")) + return LAS_EVAL_TRUE; + + /* Start with the full name. Then strip off each component + * leaving the remainder starting with a period. E.g. + * splash.mcom.com + * .mcom.com + * .com + * Search the hash table for each remaining portion. Remember that + * wildcards were put in with the leading period intact. + */ + do { + if (ACL_HashTableLookup_const(context->Table, token)) + return LAS_EVAL_TRUE; + + token = strchr(&token[1], '.'); + } while (token != NULL); + + return LAS_EVAL_FALSE; + +} + +/* LASDNSBuild + * Builds a hash table of all the hostnames provided (plus their aliases + * if aliasflg is true). Wildcards are only permitted in the leftmost + * field. They're represented in the hash table by a leading period. + * E.g. ".mcom.com". + * + * RETURNS Zero on success, else LAS_EVAL_INVALID + */ +int +LASDnsBuild(NSErr_t *errp, char *attr_pattern, LASDnsContext_t *context, int aliasflg) +{ + int delimiter; /* length of valid token */ + char token[256]; /* max length dns name */ + int i; + int ipcnt; + char **p; + unsigned long *ipaddrs=0; + pool_handle_t *pool; + PRStatus error=PR_SUCCESS; + char buffer[PR_NETDB_BUF_SIZE]; +#ifdef UTEST + struct hostent *he, host; +#else + PRHostEnt *he, host; +#endif + + context->Table = PR_NewHashTable(0, + PR_HashCaseString, + PR_CompareCaseStrings, + PR_CompareValues, + &ACLPermAllocOps, + NULL); + pool = pool_create(); + context->pool = pool; + if ((!context->Table) || (!context->pool)) { + nserrGenerate(errp, ACLERRNOMEM, ACLERR4700, ACL_Program, 1, + XP_GetAdminStr(DBT_lasdnsbuildUnableToAllocateHashT_)); + return LAS_EVAL_INVALID; + } + + do { + /* Get a single hostname from the pattern string */ + delimiter = strcspn(attr_pattern, ", \t"); + strncpy(token, attr_pattern, delimiter); + token[delimiter] = '\0'; + + /* Skip any white space after the token */ + attr_pattern += delimiter; + attr_pattern += strspn(attr_pattern, ", \t"); + + /* If there's a wildcard, strip it off but leave the "." + * Can't have aliases for a wildcard pattern. + * Treat "*" as a special case. If so, go ahead and hash it. + */ + if (token[0] == '*') { + if (token[1] != '\0') { + if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[1]), (void *)-1)) { + nserrGenerate(errp, ACLERRFAIL, ACLERR4710, ACL_Program, 2, + XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token); + return LAS_EVAL_INVALID; + } + } else { + if (!PR_HashTableAdd(context->Table, pool_strdup(pool, token), (void *)-1)) { + nserrGenerate(errp, ACLERRFAIL, ACLERR4720, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token); + return LAS_EVAL_INVALID; + } + } + } else { + /* This is a single hostname add it to the hash table */ + if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[0]), (void *)-1)) { + nserrGenerate(errp, ACLERRFAIL, ACLERR4730, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token); + return LAS_EVAL_INVALID; + } + + if (aliasflg) { + /* memset(buffer, '\0', PR_NETDB_BUF_SIZE); + */ +#ifdef UTEST + he = gethostbyname(token); +#else + error = PR_GetHostByName(token, + buffer, + PR_NETDB_BUF_SIZE, + &host); + if (error == PR_SUCCESS) he = &host; + else he = NULL; +#endif + if (he) { + /* Make a copy of the list of IP addresses if any */ + if (he->h_addr_list && he->h_addr_list[0]) { + + /* Count the IP addresses */ + for (p = he->h_addr_list, ipcnt = 0; *p; ++p) { + ++ipcnt; + } + + /* Allocate space */ + ipaddrs = (unsigned long *)PERM_MALLOC(ipcnt * sizeof(unsigned long)); + + /* Copy IP addresses */ + for (i = 0; i < ipcnt; ++i) { + ipaddrs[i] = 0; + memcpy((void *)&ipaddrs[i], he->h_addr_list[i], 4); + } + } + + /* Add each of the aliases to the list */ + if (he->h_aliases && he->h_aliases[0]) { + + for (p = he->h_aliases; *p; ++p) { + /* Add it to the hash table */ + if (!PR_HashTableAdd(context->Table, pool_strdup(pool, *p), (void*)-1)) { + nserrGenerate(errp, ACLERRFAIL, ACLERR4740, ACL_Program, 2, + XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), *p); + PERM_FREE(ipaddrs); + return LAS_EVAL_INVALID; + } + } + } + + for (i = 0; i < ipcnt; ++i) { + +#ifdef UTEST + he = gethostbyaddr((char *)&ipaddrs[i], 4, AF_INET); +#else + error = PR_GetHostByAddr((PRNetAddr *)&ipaddrs[i], + buffer, + PR_NETDB_BUF_SIZE, + &host); + if (error == PR_SUCCESS) he = &host; + else he = NULL; +#endif + if (he) { + if (he->h_name) { + /* Add it to the hash table */ + if (!PR_HashTableAdd(context->Table, pool_strdup(pool, he->h_name), + (void *)-1)) { + nserrGenerate(errp, ACLERRFAIL, ACLERR4750, ACL_Program, 2, + XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), he->h_name); + PERM_FREE(ipaddrs); + return LAS_EVAL_INVALID; + } + } + + if (he->h_aliases && he->h_aliases[0]) { + for (p = he->h_aliases; *p; ++p) { + /* Add it to the hash table */ + if (!PR_HashTableAdd(context->Table, pool_strdup(pool, *p), (void *)-1)) { + nserrGenerate(errp, ACLERRFAIL, ACLERR4760, ACL_Program, 2, + XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), *p); + PERM_FREE(ipaddrs); + return LAS_EVAL_INVALID; + } + } + } + } + } + + PERM_FREE(ipaddrs); + + } /* if he */ + + + } /* if aliasflg */ + + } /* else - single hostname */ + + + } while ((attr_pattern != NULL) && + (attr_pattern[0] != '\0') && + (delimiter != (int)NULL)); + + return 0; +} + +/* LASDnsFlush + * Given the address of a las_cookie for a DNS expression entry, frees up + * all allocated memory for it. This includes the hash table, plus the + * context structure. + */ +void +LASDnsFlush(void **las_cookie) +{ + if (*las_cookie == NULL) + return; + + pool_destroy(((LASDnsContext_t *)*las_cookie)->pool); + PR_HashTableDestroy(((LASDnsContext_t *)*las_cookie)->Table); + PERM_FREE(*las_cookie); + *las_cookie = NULL; + return; +} + +/* + * LASDnsEval + * INPUT + * attr_name The string "dns" - in lower case. + * comparator CMP_OP_EQ or CMP_OP_NE only + * attr_pattern A comma-separated list of DNS names + * Any segment(s) in a DNS name can be wildcarded using + * "*". Note that this is not a true Regular Expression + * form. + * *cachable Always set to ACL_INDEF_CACHE + * subject Subject property list + * resource Resource property list + * auth_info Authentication info, if any + * RETURNS + * ret code The usual LAS return codes. + */ +int LASDnsEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, + char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie, + PList_t subject, PList_t resource, + PList_t auth_info, PList_t global_auth) +{ + int result; + int aliasflg; + char *my_dns; + LASDnsContext_t *context; + int rv; + + *cachable = ACL_INDEF_CACHABLE; + + if (strcmp(attr_name, "dns") == 0) + aliasflg = 0; + else if (strcmp(attr_name, "dnsalias") == 0) + aliasflg = 1; + else { + nserrGenerate(errp, ACLERRINVAL, ACLERR4800, ACL_Program, 2, XP_GetAdminStr(DBT_lasDnsBuildReceivedRequestForAtt_), attr_name); + return LAS_EVAL_INVALID; + } + + if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) { + nserrGenerate(errp, ACLERRINVAL, ACLERR4810, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalIllegalComparatorDN_), comparator_string(comparator)); + return LAS_EVAL_INVALID; + } + + /* If this is the first time through, build the pattern tree first. */ + if (*LAS_cookie == NULL) { + ACL_CritEnter(); + if (*LAS_cookie == NULL) { /* Must check again */ + *LAS_cookie = context = + (LASDnsContext_t *)PERM_MALLOC(sizeof(LASDnsContext_t)); + if (context == NULL) { + nserrGenerate(errp, ACLERRNOMEM, ACLERR4820, ACL_Program, 1, XP_GetAdminStr(DBT_lasdnsevalUnableToAllocateContex_)); + ACL_CritExit(); + return LAS_EVAL_FAIL; + } + context->Table = NULL; + LASDnsBuild(errp, attr_pattern, context, aliasflg); + } + ACL_CritExit(); + } else + context = (LASDnsContext *) *LAS_cookie; + + /* Call the DNS attribute getter */ +#ifdef UTEST + LASDnsGetDns(&my_dns); /* gets stuffed on return */ +#else + rv = ACL_GetAttribute(errp, ACL_ATTR_DNS, (void **)&my_dns, + subject, resource, auth_info, global_auth); + + if (rv != LAS_EVAL_TRUE) { + if (subject || resource) { + char rv_str[16]; + /* Don't ereport if called from ACL_CachableAclList */ + sprintf(rv_str, "%d", rv); + nserrGenerate(errp, ACLERRINVAL, ACLERR4830, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalUnableToGetDnsErrorDN_), rv_str); + } + return LAS_EVAL_FAIL; + } +#endif + + result = LASDnsMatch(my_dns, context); + + if (comparator == CMP_OP_NE) { + if (result == LAS_EVAL_FALSE) + return LAS_EVAL_TRUE; + else if (result == LAS_EVAL_TRUE) + return LAS_EVAL_FALSE; + } + return (result); +} |