NSAPI_PUBLIC ACLListHandle_t * ACL_ParseString( NSErr_t *errp, char *buffer ) { ACLListHandle_t *handle = NULL; int eid = 0; int rv = 0; const char *errmsg; ACL_InitAttr2Index(); if ( acl_parse_crit == NULL ) acl_parse_crit = crit_init(); crit_enter( acl_parse_crit ); if ( acl_InitScanner( errp, NULL, buffer ) < 0 ) { rv = ACLERRNOMEM; eid = ACLERR1920; nserrGenerate(errp, rv, eid, ACL_Program, 0); } else { handle = ACL_ListNew(errp); if ( handle == NULL ) { rv = ACLERRNOMEM; eid = ACLERR1920; nserrGenerate(errp, rv, eid, ACL_Program, 0); } else if ( acl_PushListHandle( handle ) < 0 ) { rv = ACLERRNOMEM; eid = ACLERR1920; nserrGenerate(errp, rv, eid, ACL_Program, 0); } else if ( acl_Parse() ) { rv = ACLERRPARSE; eid = ACLERR1780; } if ( acl_EndScanner() < 0 ) { rv = ACLERROPEN; eid = ACLERR1500; errmsg = system_errmsg(); nserrGenerate(errp, rv, eid, ACL_Program, 2, "buffer", errmsg); } } if ( rv || eid ) { ACL_ListDestroy(errp, handle); handle = NULL; } crit_exit( acl_parse_crit ); return(handle); }
NSAPI_PUBLIC int ACL_ListPostParseForAuth(NSErr_t *errp, ACLListHandle_t *acl_list ) { ACLHandle_t *acl; ACLWrapper_t *wrap; ACLExprHandle_t *expr; char *method; char *database; int rv; ACLDbType_t *dbtype; ACLMethod_t *methodtype; if ( acl_list == NULL ) return(0); // for all ACLs for ( wrap = acl_list->acl_list_head; wrap; wrap = wrap->wrap_next ) { acl = wrap->acl; if ( acl == NULL ) continue; // for all expressions with the ACL for ( expr = acl->expr_list_head; expr; expr = expr->expr_next ) { if ( expr->expr_type != ACL_EXPR_TYPE_AUTH || expr->expr_auth == NULL) continue; // get method attribute - this is a name now rv = PListGetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX, (void **) &method, NULL); if ( rv >= 0 ) { methodtype = (ACLMethod_t *)PERM_MALLOC(sizeof(ACLMethod_t)); rv = ACL_MethodFind(errp, method, methodtype); if (rv < 0) { nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program, 3, acl->tag, "method", method); PERM_FREE(methodtype); return(ACLERRUNDEF); } // replace it with a method type rv = PListSetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX, methodtype, NULL); if ( rv < 0 ) { nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program, 0); return(ACLERRNOMEM); } PERM_FREE(method); } } } return(0); }
/* LASIpTreeAlloc * Malloc a node and set the actions to LAS_EVAL_FALSE */ static LASIpTree_t * LASIpTreeAllocNode(NSErr_t *errp) { LASIpTree_t *newnode; newnode = (LASIpTree_t *)PERM_MALLOC(sizeof(LASIpTree_t)); if (newnode == NULL) { nserrGenerate(errp, ACLERRNOMEM, ACLERR5000, ACL_Program, 1, XP_GetAdminStr(DBT_lasiptreeallocNoMemoryN_)); return NULL; } newnode->action[0] = (LASIpTree_t *)LAS_EVAL_FALSE; newnode->action[1] = (LASIpTree_t *)LAS_EVAL_FALSE; return newnode; }
/* * traverseTreeAndCompareIPs * This function compares bit by bit of IP address with the tree nodes * Input * NSErr_t *errp * PRNetAddr * ip_addr - IP address of the client * LASIpContext *context * char * attr_pattern - ip address/pattern passed into LASIpEval * int ipVersion - ipVersion of clients IP Address * bool comparator_is_equal - true if comparator is CMP_OP_EQ * Returns * LAS_EVAL_TRUE or LAS_EVAL_FALSE, or LAS_* error codes in case of error. */ int traverseTreeAndCompareIPs(NSErr_t *errp, PRNetAddr *ip_addr, LASIpContext *context, char *attr_pattern, int ipVersion, bool comparator_is_equal) { // special case ip=* if (context->ipVersion == (PR_AF_INET6+PR_AF_INET)) { if (comparator_is_equal) { ereport(LOG_VERBOSE, "acl ip: match on ip = (%s)", attr_pattern); return(LAS_EVAL_TRUE); } else { ereport(LOG_VERBOSE, "acl ip: no match on ip != (%s)", attr_pattern); return(LAS_EVAL_FALSE); } } LASIpTree_t *node = context->treetop; if (context->ipVersion != ipVersion || node == NULL) { ereport(LOG_VERBOSE, "ERROR IP Address returned by Attribute Getter for ACL_ATTR_IP did not match with IP Address Version set in ACL file."); if (comparator_is_equal) { return(LAS_EVAL_FALSE); } else { return(LAS_EVAL_TRUE); } } int max_bits=32; if (ipVersion == PR_AF_INET6) max_bits=128; else if (ipVersion != PR_AF_INET) return LAS_EVAL_INVALID; for (int bit=(max_bits-1); bit >=0; bit--) { int value = getBit(*ip_addr,bit,max_bits); if (LAS_IP_IS_CONSTANT(node->action[value])) { /* Reached a result, so return it */ int r = (int)(size_t) node->action[value]; if (comparator_is_equal) { ereport(LOG_VERBOSE, "acl ip: %s on ip = (%s)", (r == LAS_EVAL_TRUE) ? "match" : "no match", attr_pattern); return(r); } else { ereport(LOG_VERBOSE, "acl ip: %s on ip != (%s)", (r == LAS_EVAL_TRUE) ? "no match" : "match", attr_pattern); return((r == LAS_EVAL_TRUE) ? LAS_EVAL_FALSE : LAS_EVAL_TRUE); } } else { /* Move on to the next bit */ node = node->action[value]; } } /* Cannot reach here. Even a 32 bit mismatch has a conclusion in * the pattern tree. */ char ip_str[124]; memset(ip_str,0,124); PR_NetAddrToString(ip_addr,ip_str,124); nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), max_bits, ip_str); return LAS_EVAL_INVALID; }
/* * LASIpEval * INPUT * attr_name The string "ip" - in lower case. * comparator CMP_OP_EQ or CMP_OP_NE only * attr_pattern A comma-separated list of IP addresses and netmasks * in dotted-decimal form. Netmasks are optionally * prepended to the IP address using a plus sign. E.g. * 255.255.255.0+123.45.67.89. Any byte in the IP address * (but not the netmask) can be wildcarded using "*" * *cachable Always set to ACL_INDEF_CACHABLE * subject Subject property list * resource Resource property list * auth_info The authentication info if any * RETURNS * ret code The usual LAS return codes. */ int LASIpEval(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) { void *pip; int retcode; LASIpContext_t *context; int rv; #ifndef UTEST *cachable = ACL_INDEF_CACHABLE; #endif if (strcmp(attr_name, "ip") != 0) { nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2, XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name); return LAS_EVAL_INVALID; } if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) { nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator)); return LAS_EVAL_INVALID; } /* GET THE IP ADDR FROM THE SESSION CONTEXT AND STORE IT IN THE * VARIABLE ip. */ #ifndef UTEST rv = ACL_GetAttribute(errp, ACL_ATTR_IP, &pip, subject, resource, auth_info, global_auth); PRNetAddr *ip_addr = (PRNetAddr *)pip; if (rv != LAS_EVAL_TRUE) { if (subject || resource) { /* Don't ereport if called from ACL_CachableAclList */ char rv_str[16]; sprintf(rv_str, "%d", rv); nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str); } ereport(LOG_VERBOSE, "ERROR Attribute Getter for ACL_ATTR_IP returned error %d.", rv); return LAS_EVAL_FAIL; } #else PRNetAddr *ip_addr = LASIpGetIpv6(); if (ip_addr == NULL) { ereport(LOG_VERBOSE, "ERROR IP Address returned from LASIpGetIpv6() is NULL."); return LAS_EVAL_FAIL; } #endif int ipVersion = PR_AF_INET; if (ip_addr->ipv6.family == PR_AF_INET6) { ipVersion = PR_AF_INET6; } else if (ip_addr->inet.family != PR_AF_INET) { PR_ASSERT(0); } /* If this is the first time through, build the pattern tree first. */ if (*LAS_cookie == NULL) { if (strcspn(attr_pattern, "0123456789.*ABCDEF:abcdef,+ \t")) { nserrGenerate(errp,ACLERRINVAL,ACLERR5120,ACL_Program,2, XP_GetAdminStr(DBT_lasIpIncorrentIPPattern),attr_pattern); return LAS_EVAL_INVALID; } ACL_CritEnter(); context = (LASIpContext *) *LAS_cookie; if (*LAS_cookie == NULL) { /* must check again */ *LAS_cookie = context = (LASIpContext_t *)PERM_MALLOC(sizeof(LASIpContext_t)); if (context == NULL) { nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1, XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_)); ACL_CritExit(); return LAS_EVAL_FAIL; } context->treetop = NULL; retcode = LASIpBuild(errp, attr_pattern, &context->treetop, ipVersion); if ((retcode == PR_AF_INET6) || (retcode == PR_AF_INET) || (retcode == (PR_AF_INET6+PR_AF_INET))) context->ipVersion = retcode; else { ACL_CritExit(); return (retcode); } } ACL_CritExit(); } else context = (LASIpContext *) *LAS_cookie; return traverseTreeAndCompareIPs(errp, ip_addr, context, attr_pattern, ipVersion, (comparator == CMP_OP_EQ)?1:0); }
/* LASIpAddPattern * Takes a netmask and IP address and a pointer to an existing IP * tree and adds nodes as appropriate to recognize the new pattern. * INPUT * netmask netmask in PRNetAddr * pattern IP address in PRNetAddr * *treetop An existing IP tree or 0 if a new tree * ipVersion int PR_AF_INET or PR_AF_INET6 * RETURNS * ret code NULL on success, ACL_RES_ERROR on failure * **treetop If this is a new tree, the head of the tree. */ static int LASIpAddPattern(NSErr_t *errp, PRNetAddr netmask, PRNetAddr pattern, LASIpTree_t **treetop, int ipVersion) { int stopbit; /* Don't care after this point */ int curbit; /* current bit we're working on */ int curval; /* value of pattern[curbit] */ LASIpTree_t *curptr; /* pointer to the current node */ LASIpTree_t *newptr; int max_bit = 32; if (ipVersion == PR_AF_INET6) max_bit = 128; else if (ipVersion != PR_AF_INET) return LAS_EVAL_INVALID; /* stop at the first 1 in the netmask from low to high */ for (stopbit=0; stopbit<max_bit; stopbit++) { if (getBit(netmask,stopbit,max_bit) != 0) break; } /* Special case if there's no tree. Allocate the first node */ if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */ curptr = LASIpTreeAllocNode(errp); if (curptr == NULL) { nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_)); return ACL_RES_ERROR; } *treetop = curptr; } else curptr = *treetop; /* Special case if the netmask is 0. */ if (stopbit > (max_bit -1)) { curptr->action[0] = (LASIpTree_t *)LAS_EVAL_TRUE; curptr->action[1] = (LASIpTree_t *)LAS_EVAL_TRUE; return 0; } /* follow the tree down the pattern path bit by bit until the * end of the tree is reached (i.e. a constant). */ for (curbit=max_bit-1,curptr=*treetop; curbit >= 0; curbit--) { /* Is the current bit ON? If so set curval to 1 else 0 */ curval = getBit(pattern, curbit, max_bit); /* Are we done, if so remove the rest of the tree */ if (curbit == stopbit) { LASIpTreeDealloc(curptr->action[curval]); curptr->action[curval] = (LASIpTree_t *)LAS_EVAL_TRUE; /* This is the normal exit point. Most other * exits must be due to errors. */ return 0; } /* Oops reached the end - must allocate */ if (LAS_IP_IS_CONSTANT(curptr->action[curval])) { newptr = LASIpTreeAllocNode(errp); if (newptr == NULL) { LASIpTreeDealloc(*treetop); nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1)); return ACL_RES_ERROR; } curptr->action[curval] = newptr; } /* Keep going down the tree */ curptr = curptr->action[curval]; } return ACL_RES_ERROR; }
/* * LASIsLockOwnerEval * INPUT * attr_name The string "is-lock-owner" - in lower case. * comparator CMP_OP_EQ or CMP_OP_NE only * attr_pattern "on", "off", "yes", "no", "true", "false", "1", "0" * cachable Always set to ACL_NOT_CACHABLE. * subject Subject property list * resource Resource property list * auth_info Authentication info, if any * RETURNS * retcode The usual LAS return codes. */ int LASIsLockOwnerEval(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 retcode=0; int matched=0; char *lock_owner=NULL; char *user=NULL; PRBool pattern=PR_TRUE; int rv=0; *cachable = ACL_NOT_CACHABLE; *LAS_cookie = (void *)0; if (strcmp(attr_name, ACL_ATTR_IS_LOCK_OWNER)) { nserrGenerate(errp, ACLERRINVAL, ACLERR6700, ACL_Program, 2, XP_GetAdminStr(DBT_lasIsLockOwnerEvalReceivedRequestForAtt_), attr_name); return LAS_EVAL_INVALID; } if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) { nserrGenerate(errp, ACLERRINVAL, ACLERR6710, ACL_Program, 2, XP_GetAdminStr(DBT_lasIsLockOwnerEvalIllegalComparatorDN_), comparator_string(comparator)); return LAS_EVAL_INVALID; } if (PL_strcasecmp(attr_pattern, "on") == 0 || PL_strcasecmp(attr_pattern, "true") == 0 || PL_strcasecmp(attr_pattern, "yes") == 0 || PL_strcasecmp(attr_pattern, "1") == 0) { pattern = PR_TRUE; } else if (PL_strcasecmp(attr_pattern, "off") == 0 || PL_strcasecmp(attr_pattern, "false") == 0 || PL_strcasecmp(attr_pattern, "no") == 0 || PL_strcasecmp(attr_pattern, "0") == 0) { pattern = PR_FALSE; } else { nserrGenerate(errp, ACLERRINVAL, ACLERR6720, ACL_Program, 2, XP_GetAdminStr(DBT_lasIsLockOwnerEvalIllegalAttrPattern_), attr_pattern); return LAS_EVAL_INVALID; } // get the lock owner // assuming lock owner has been set in plist before ACL_Evaluate is called rv = ACL_GetAttribute(errp, ACL_ATTR_LOCK_OWNER, (void **)&lock_owner, subject, resource, auth_info, global_auth); if (rv != LAS_EVAL_TRUE) { return rv; } if (lock_owner) { // get the authenticated user name rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&user, subject, resource, auth_info, global_auth); if (rv != LAS_EVAL_TRUE) { return rv; } if (user) { // if user is the lock owner matched = !strcmp(user, lock_owner); } else // user has not been authenticated yet matched=0; } else // lock owner is null means does not match matched=0; if (pattern == PR_FALSE) matched = !matched; if (comparator == CMP_OP_EQ) { retcode = (matched ? LAS_EVAL_TRUE : LAS_EVAL_FALSE); } else { retcode = (matched ? LAS_EVAL_FALSE : LAS_EVAL_TRUE); } ereport(LOG_VERBOSE, "acl is-lock-owner : user [%s] %s is lock owner [%s] %s (%s)", user?user:"", (retcode == LAS_EVAL_FALSE) ? "does not match" : (retcode == LAS_EVAL_TRUE) ? "matched" : "error in", lock_owner?lock_owner:"", (comparator == CMP_OP_EQ) ? "=" : "!=", attr_pattern); return retcode; }
/* * 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 = NULL; int rv; *cachable = ACL_INDEF_CACHABLE; if (strcmp(attr_name, "dns") == 0) { /* Enable aliasflg for "dns", which allows "dns" hostname to look up * DSN hash table using the primary hostname. */ aliasflg = 1; } 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; if (LASDnsBuild(errp, attr_pattern, context, aliasflg) == LAS_EVAL_INVALID) { /* Error is already printed in LASDnsBuild */ ACL_CritExit(); return LAS_EVAL_FAIL; } /* After this line, it is assured context->Table is not NULL. */ } else { context = (LASDnsContext *) *LAS_cookie; } ACL_CritExit(); } else { ACL_CritEnter(); context = (LASDnsContext *) *LAS_cookie; ACL_CritExit(); } /* 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); }
/* 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) { size_t delimiter; /* length of valid tokeni */ char token[256]; /* max length dns name */ int i; char **p; 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 char *end_attr_pattern; if (attr_pattern == NULL) { nserrGenerate(errp, ACLERRINVAL, ACLERR4770, ACL_Program, 1, XP_GetAdminStr(DBT_lasdnsbuildInvalidAttributePattern_)); return LAS_EVAL_INVALID; } 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; } end_attr_pattern = attr_pattern + strlen(attr_pattern); do { size_t maxsize = sizeof(token); /* Get a single hostname from the pattern string */ delimiter = strcspn(attr_pattern, ", \t"); if (delimiter >= maxsize) { delimiter = maxsize-1; } PL_strncpyz(token, attr_pattern, delimiter + 1); token[delimiter] = '\0'; /* Skip any white space after the token */ attr_pattern += delimiter; if (attr_pattern < end_attr_pattern) { 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) { void *iter = NULL; int addrcnt = 0; PRNetAddr *netaddr = (PRNetAddr *)PERM_CALLOC(sizeof(PRNetAddr)); PRAddrInfo *infop = PR_GetAddrInfoByName(token, PR_AF_UNSPEC, (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME)); if (!netaddr) { if (infop) { PR_FreeAddrInfo(infop); } return LAS_EVAL_NEED_MORE_INFO; /* hostname not known to dns? */ } if (!infop) { if (netaddr) { PERM_FREE(netaddr); } return LAS_EVAL_NEED_MORE_INFO; /* hostname not known to dns? */ } /* need to count the address, first */ while ((iter = PR_EnumerateAddrInfo(iter, infop, 0, netaddr))) { addrcnt++; } if (0 == addrcnt) { PERM_FREE(netaddr); PR_FreeAddrInfo(infop); return LAS_EVAL_NEED_MORE_INFO; /* hostname not known to dns? */ } iter = NULL; /* from the beginning */ memset(netaddr, 0, sizeof(PRNetAddr)); for (i = 0; i < addrcnt; i++) { iter = PR_EnumerateAddrInfo( iter, infop, 0, netaddr ); if (NULL == iter) { break; } error = PR_GetHostByAddr(netaddr, buffer, PR_NETDB_BUF_SIZE, &host); if (error == PR_SUCCESS) { he = &host; } else { continue; } 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(netaddr); PR_FreeAddrInfo(infop); 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(netaddr); PR_FreeAddrInfo(infop); return LAS_EVAL_INVALID; } } } } /* for (i = 0; i < addrcnt; i++) */ PERM_FREE(netaddr); PR_FreeAddrInfo(infop); } /* if aliasflg */ } /* else - single hostname */ } while ((attr_pattern != NULL) && (attr_pattern[0] != '\0') && (delimiter != 0)); return 0; }
NSAPI_PUBLIC int ACL_ListPostParseForAuth(NSErr_t *errp, ACLListHandle_t *acl_list ) { ACLHandle_t *acl; ACLWrapper_t *wrap; ACLExprHandle_t *expr; char *method; char *database; int rv; ACLDbType_t *dbtype; ACLMethod_t *methodtype; if ( acl_list == NULL ) return(0); for ( wrap = acl_list->acl_list_head; wrap; wrap = wrap->wrap_next ) { acl = wrap->acl; if ( acl == NULL ) continue; for ( expr = acl->expr_list_head; expr; expr = expr->expr_next ) { if ( expr->expr_type != ACL_EXPR_TYPE_AUTH || expr->expr_auth == NULL) continue; rv = PListGetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX, (void **) &method, NULL); if ( rv >= 0 ) { methodtype = (ACLMethod_t *)PERM_MALLOC(sizeof(ACLMethod_t)); rv = ACL_MethodFind(errp, method, methodtype); if (rv) { nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program, 3, acl->tag, "method", method); PERM_FREE(methodtype); return(ACLERRUNDEF); } rv = PListSetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX, methodtype, NULL); if ( rv < 0 ) { nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program, 0); return(ACLERRNOMEM); } PERM_FREE(method); } rv = PListGetValue(expr->expr_auth, ACL_ATTR_DATABASE_INDEX, (void **) &database, NULL); if (rv < 0) continue; /* The following function lets user use databases which are * not registered by their administrators. This also fixes * the backward compatibility. */ dbtype = (ACLDbType_t *)PERM_MALLOC(sizeof(ACLDbType_t)); rv = ACL_RegisterDbFromACL(errp, (const char *) database, dbtype); if (rv < 0) { nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program, 3, acl->tag, "database", database); PERM_FREE(dbtype); return(ACLERRUNDEF); } rv = PListInitProp(expr->expr_auth, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE, dbtype, NULL); if ( rv < 0 ) { nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program, 0); return(ACLERRNOMEM); } } } return(0); }
/* * LASUserEval * INPUT * attr_name The string "user" - in lower case. * comparator CMP_OP_EQ or CMP_OP_NE only * attr_pattern A comma-separated list of users * *cachable Always set to ACL_NOT_CACHABLE. * subject Subject property list * resource Resource property list * auth_info Authentication info, if any * RETURNS * retcode The usual LAS return codes. */ int LASUserEval(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) { char *uid; char *users; char *user; char *comma; int retcode; int matched; int is_owner; int rv; *cachable = ACL_NOT_CACHABLE; *LAS_cookie = (void *)0; if (strcmp(attr_name, ACL_ATTR_USER) != 0) { nserrGenerate(errp, ACLERRINVAL, ACLERR5700, ACL_Program, 2, XP_GetAdminStr(DBT_lasUserEvalReceivedRequestForAtt_), attr_name); return LAS_EVAL_INVALID; } if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) { nserrGenerate(errp, ACLERRINVAL, ACLERR5710, ACL_Program, 2, XP_GetAdminStr(DBT_lasuserevalIllegalComparatorDN_), comparator_string(comparator)); return LAS_EVAL_INVALID; } if (!strcmp(attr_pattern, "anyone")) { *cachable = ACL_INDEF_CACHABLE; return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE; } /* get the authenticated user name */ #ifndef UTEST rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid, subject, resource, auth_info, global_auth); if (rv != LAS_EVAL_TRUE) { return rv; } #else uid = (char *)LASUserGetUser(); #endif /* We have an authenticated user */ if (!strcmp(attr_pattern, "all")) { return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE; } users = STRDUP(attr_pattern); if (!users) { nserrGenerate(errp, ACLERRNOMEM, ACLERR5720, ACL_Program, 1, XP_GetAdminStr(DBT_lasuserevalRanOutOfMemoryN_)); return LAS_EVAL_FAIL; } user = users; matched = 0; /* check if the uid is one of the users */ while(user != 0 && *user != 0 && !matched) { if ((comma = strchr(user, ',')) != NULL) { *comma++ = 0; } /* ignore leading whitespace */ while(*user == ' ' || *user == '\t') user++; if (*user) { /* ignore trailing whitespace */ int len = strlen(user); char *ptr = user+len-1; while(*ptr == ' ' || *ptr == '\t') *ptr-- = 0; } if (!strcasecmp(user, ACL_ATTR_OWNER)) { rv = ACL_GetAttribute(errp, ACL_ATTR_IS_OWNER, (void **)&is_owner, subject, resource, auth_info, global_auth); if (rv == LAS_EVAL_TRUE) matched = 1; else /* continue checking for next user */ user = comma; } else if (!WILDPAT_CASECMP(uid, user)) { /* uid is one of the users */ matched = 1; } else { /* continue checking for next user */ user = comma; } } if (comparator == CMP_OP_EQ) { retcode = (matched ? LAS_EVAL_TRUE : LAS_EVAL_FALSE); } else { retcode = (matched ? LAS_EVAL_FALSE : LAS_EVAL_TRUE); } FREE(users); return retcode; }
/* SSL LAS driver * Note that everything is case-insensitive. * INPUT * attr must be the string "ssl". * comparator can only be "=" or "!=". * pattern "on", "off", "yes", "no", "true", "false", "1", "0" * OUTPUT * cachable Will be set to ACL_NOT_CACHABLE. * return code set to LAS_EVAL_* */ int LASSSLEval(NSErr_t *errp, char *attr, CmpOp_t comparator, char *pattern, ACLCachable_t *cachable, void **las_cookie, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth) { Session *sn = NULL; PRBool sslrequired, sslstate; int rv; /* Sanity checking */ if (strcmp(attr, "ssl") != 0) { nserrGenerate(errp, ACLERRINVAL, ACLERR6300, ACL_Program, 2, XP_GetAdminStr(DBT_sslLasUnexpectedAttribute), attr); return LAS_EVAL_INVALID; } if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) { nserrGenerate(errp, ACLERRINVAL, ACLERR6310, ACL_Program, 2, XP_GetAdminStr(DBT_sslLasIllegalComparator), comparator_string(comparator)); return LAS_EVAL_INVALID; } *cachable = ACL_NOT_CACHABLE; // ???? if (PL_strcasecmp(pattern, "on") == 0 || PL_strcasecmp(pattern, "true") == 0 || PL_strcasecmp(pattern, "yes") == 0 || PL_strcasecmp(pattern, "1") == 0) { sslrequired = PR_TRUE; } else if (PL_strcasecmp(pattern, "off") == 0 || PL_strcasecmp(pattern, "false") == 0 || PL_strcasecmp(pattern, "no") == 0 || PL_strcasecmp(pattern, "0") == 0) { sslrequired = PR_FALSE; } else { nserrGenerate(errp, ACLERRINVAL, ACLERR6320, ACL_Program, 2, XP_GetAdminStr(DBT_sslLasIllegalValue), pattern); return LAS_EVAL_INVALID; } // Now look whether our session is over SSL if (PListGetValue(subject, ACL_ATTR_SESSION_INDEX, (void **)&sn, NULL) < 0) { nserrGenerate(errp, ACLERRINVAL, ACLERR6330, ACL_Program, 2, XP_GetAdminStr(DBT_sslLasUnableToGetSessionAddr)); return LAS_EVAL_FAIL; } sslstate = GetSecurity(sn); if ((sslstate == sslrequired) && (comparator == CMP_OP_EQ)) { rv = LAS_EVAL_TRUE; } else if ((sslstate != sslrequired) && (comparator == CMP_OP_NE)) { rv = LAS_EVAL_TRUE; } else { rv = LAS_EVAL_FALSE; } ereport(LOG_VERBOSE, "acl ssl: %s on ssl %s (%s)", (rv == LAS_EVAL_FALSE) ? "no match" : "match", (comparator == CMP_OP_EQ) ? "=" : "!=", pattern); return rv; }
// // ACL_GetAttribute - find and call one or more matching attribute getter functions // NSAPI_PUBLIC int ACL_GetAttribute(NSErr_t *errp, const char *attr, void **val, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth) { int rv; void *attrval; ACLAttrGetterFn_t func; ACLAttrGetterList_t getters; ACLAttrGetter_t *getter; ACLMethod_t method; char *dbname; ACLDbType_t dbtype; /* If subject PList is NULL, we will fail anyway */ if (!subject) return LAS_EVAL_FAIL; /* Is the attribute already present in the subject property list? */ rv = PListFindValue(subject, attr, &attrval, NULL); if (rv >= 0) { /* Yes, take it from there */ *val = attrval; return LAS_EVAL_TRUE; } /* Get the authentication method and database type */ // XXX umm... for ACLs that do not depend on user databases and authentication // methods (like cipher, dns, ip, tod!), we do not need method and database type. // so there's no reason to fail if we don't find anything here. // I think setting method to ACL_METHOD_ANY and dbtype to ACL_DBTYPE_ANY would // do the job in attr_getter_is_matching - this way, we would find only attr // getters that do not care about method and dbtype. if (ACL_AuthInfoGetMethod(errp, auth_info, &method) < 0) { nserrGenerate(errp, ACLERRFAIL, ACLERR4300, ACL_Program, 2, XP_GetAdminStr(DBT_GetAttributeCouldntDetermineMethod), attr); return LAS_EVAL_FAIL; } // dbtype is cached by our friendly ACLEvalAce caller (it's constant for the ACE) // XXX what if we don't get called by ACLEvalAce? if (PListGetValue(resource, ACL_ATTR_DBTYPE_INDEX, &dbtype, NULL) < 0) { dbtype = ACL_DBTYPE_INVALID; } /* Get the list of attribute getters */ if ((ACL_AttrGetterFind(errp, attr, &getters) < 0) || (getters == 0)) { nserrGenerate(errp, ACLERRFAIL, ACLERR4310, ACL_Program, 2, XP_GetAdminStr(DBT_GetAttributeCouldntLocateGetter), attr); return LAS_EVAL_DECLINE; } // Iterate over each getter and see if it should be called // Call each matching getter until a getter which doesn't decline is // found. char * method_name = NULL; char * dbtype_name = NULL; for (getter = ACL_AttrGetterFirst(&getters); getter != 0; getter = ACL_AttrGetterNext(&getters, getter)) { /* Require matching method and database type */ if (!attr_getter_is_matching(errp, getter, method, dbtype)) continue; if (ereport_can_log(LOG_VERBOSE)) { method_name = acl_get_name(ACLMethodHash, method); dbtype_name = acl_get_name(ACLDbTypeHash, dbtype); ereport(LOG_VERBOSE, "acl: calling getter for (attr=%s; " "method=%s, dbtype=%s)", attr, method_name, dbtype_name); } /* Call the getter function */ func = getter->fn; rv = (*func)(errp, subject, resource, auth_info, global_auth, getter->arg); if (method_name) { ereport(LOG_VERBOSE, "acl: getter for (attr=%s; " "method=%s, dbtype=%s) returns %d", attr, method_name, dbtype_name, rv); FREE(method_name); FREE(dbtype_name); } // if the getter declined, let's try to find another one if (rv == LAS_EVAL_DECLINE) continue; /* Did the getter succeed? */ if (rv == LAS_EVAL_TRUE) { /* * Yes, it should leave the attribute on the subject * property list. */ if (PListFindValue(subject, attr, (void **)&attrval, NULL) < 0) { nserrGenerate(errp, ACLERRFAIL, ACLERR4320, ACL_Program, 2, XP_GetAdminStr(DBT_GetAttributeDidntSetAttr), attr); return LAS_EVAL_FAIL; } /* Got it */ *val = attrval; return LAS_EVAL_TRUE; } else { /* No, did it fail to get the attribute */ if (rv == LAS_EVAL_FAIL || rv == LAS_EVAL_INVALID) { nserrGenerate(errp, ACLERRFAIL, ACLERR4330, ACL_Program, 2, XP_GetAdminStr(DBT_GetAttributeDidntGetAttr), attr); } return rv; } } // If we fall out of the loop, all the getters declined if (ereport_can_log(LOG_VERBOSE)) { method_name = acl_get_name(ACLMethodHash, method); dbtype_name = acl_get_name(ACLDbTypeHash, dbtype); ereport(LOG_VERBOSE, "acl: unable to obtain an attribute getter for " "[%s] with method [%s] (%d), dbtype [%s] (%d)", attr, method_name, method, dbtype_name, dbtype); FREE(method_name); FREE(dbtype_name); } nserrGenerate(errp, ACLERRFAIL, ACLERR4340, ACL_Program, 2, XP_GetAdminStr(DBT_GetAttributeAllGettersDeclined), attr); return LAS_EVAL_DECLINE; }