NSAPI_PUBLIC cache_t *
cache_create(unsigned int cache_max, unsigned int hash_size,
	public_cache_functions_t *fnlist)
{
	cache_t *newentry;
	unsigned int index;

SOLARIS_PROBE(cache_create_start, "cache");

	NS_ASSERT(cache_max > 0);
	NS_ASSERT(hash_size > 0);
	NS_ASSERT(fnlist);
	if ( (newentry = (cache_t *)PERM_MALLOC(sizeof(cache_t))) == NULL) {
		ereport(LOG_FAILURE, XP_GetAdminStr(DBT_insufficientMemoryToCreateHashTa_));
SOLARIS_PROBE(cache_create_end, "cache");
		return NULL;
	}

#ifdef CACHE_DEBUG
	newentry->magic = CACHE_MAGIC;
#endif
	newentry->cache_size	= 0;
	newentry->hash_size	= hash_size;
	newentry->max_size	= cache_max;
    newentry->insert_ok = 0;
    newentry->insert_fail = 0;
    newentry->deletes = 0;
	newentry->cache_hits	= 0;
	newentry->cache_lookups = 0;
	newentry->lock 	= crit_init();
	newentry->virtual_fn	= fnlist;
	if ( (newentry->table = (cache_entry_t **)
		PERM_MALLOC((sizeof(cache_entry_t *)) * (newentry->hash_size)))
		== NULL) {
		ereport(LOG_FAILURE, XP_GetAdminStr(DBT_insufficientMemoryToCreateHashTa_1));
SOLARIS_PROBE(cache_create_end, "cache");
		return NULL;
	}
	for (index=0; index<newentry->hash_size; index++) 
		newentry->table[index] = NULL;
	newentry->mru_head = newentry->lru_head = NULL;

#ifdef IRIX
	newentry->fast_mode = 0;
	newentry->garbage_list_head = NULL;
	newentry->gc_time = 0;
#endif

	if (!cache_crit) 
		cache_crit = crit_init();
	
	crit_enter(cache_crit);
	newentry->next = cache_list;
	cache_list = newentry;
	crit_exit(cache_crit);

SOLARIS_PROBE(cache_create_end, "cache");
	return newentry;
}
Session *session_alloc(SYS_NETFD csd, struct sockaddr_in *sac)
{
    NSAPISession *nsn = (NSAPISession *)PERM_MALLOC(sizeof(NSAPISession));
    nsn->thread_data = NULL;
    nsn->httpfilter = NULL;
    nsn->input_done = PR_FALSE;
    nsn->input_os_pos = 0;
    nsn->exec_rq = NULL;
    nsn->filter_rq = NULL;
    nsn->session_clone = PR_FALSE;
    nsn->received = 0;
    nsn->transmitted = 0;

    Session *ns = &nsn->sn;
    ns->csd = csd;
    ns->iaddr = sac->sin_addr;
    ns->csd_open = 1;
    ns->fill = 0;
    ns->ssl = 0; // mark SSL off by default
    ns->clientauth = 0; // mark clientauth off by default

    ns->subject = NULL;

    ns->pr_local_addr = NULL;
    ns->pr_client_addr = NULL;

    return ns;
}
Esempio n. 3
0
NSAPI_PUBLIC int
ACL_ExprAddArg( NSErr_t *errp, 
    ACLExprHandle_t *expr, 
    const char *arg )
{

    if ( expr == NULL ) 
        return(ACLERRUNDEF);

    if (expr->expr_argv == NULL)
        expr->expr_argv = (char **) PERM_MALLOC( 2 * sizeof(char *) );
    else
        expr->expr_argv = (char **) PERM_REALLOC( expr->expr_argv,
                                        (expr->expr_argc+2)
                                        * sizeof(char *) );
    
    if (expr->expr_argv == NULL) 
        return(ACLERRNOMEM);
    
    expr->expr_argv[expr->expr_argc] = PERM_STRDUP( arg );
    if (expr->expr_argv[expr->expr_argc] == NULL) 
        return(ACLERRNOMEM);
    expr->expr_argc++;
    expr->expr_argv[expr->expr_argc] = NULL;
    
    return(0);

}
NSAPI_PUBLIC int INTnet_buffer_input(SYS_NETFD sd, int sz)
{
    NetLayer *nl = _netlayer_find(sd);
    if (nl) {
        if (sz > nl->maxsize) {
            void *inbuf = PERM_REALLOC(nl->inbuf, sz);
            if (!inbuf)
                return -1;

            nl->inbuf = (char *) inbuf;
        }

        nl->maxsize = sz;

        return 0;
    }

    nl = (NetLayer *) PERM_MALLOC(sizeof(NetLayer));
    if (!nl)
        return -1;

    nl->pos = 0;
    nl->cursize = 0;
    nl->maxsize = sz;
    nl->inbuf = (char *) PERM_MALLOC(sz);
    if (!nl->inbuf) {
        PERM_FREE(nl);
        return -1;
    }

    PRFileDesc *layer = PR_CreateIOLayerStub(_netlayer_identity, &_netlayer_methods);
    if (!layer) {
        PERM_FREE(nl->inbuf);
        PERM_FREE(nl);
        return -1;
    }

    layer->secret = (PRFilePrivate *) nl;

    PRStatus rv = PR_PushIOLayer(sd, PR_NSPR_IO_LAYER, layer);
    if (rv != PR_SUCCESS) {
        PR_Close(layer);
        return -1;
    }

    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 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;
}
//
// One-time routine for poll manager initialization.
//
PRStatus 
PollManager::Initialize(PRUint32 maxKeepAlives,
                        PRUint32 numThreads,
                        PRIntervalTime pollInterval)
{
    // Number of keepalive connections we will support
    this->maxKeepAlives_ = maxKeepAlives;

    // Number of poll threads
    this->numThreads_ = numThreads;

    log_ereport(LOG_VERBOSE, XP_GetAdminStr(DBT_PollManagerMaxKAConn),
                this->maxKeepAlives_);

    threads_ = (KAPollThread **)PERM_MALLOC(numThreads_ * sizeof(KAPollThread *));

    // Figure out the number of keep-alive connections each keep-alive poll
    // thread should accomodate then add some margin for acceptors and newly
    // accepted connections
    PRInt32 numDescPerThread = (maxKeepAlives_ + numThreads_) / numThreads_ + 1;

    PRUint32 i;

    PRStatus status = PR_SUCCESS;
    if (threads_)
    {
        // Initialize the poll arrays and start those poll threads.
        for (i = 0; i < this->numThreads_; i++)
        {
            KAPollThread *thr = new KAPollThread(this, numDescPerThread, pollInterval);
            if (thr)
                status = thr->start(PR_GLOBAL_BOUND_THREAD, PR_UNJOINABLE_THREAD);
            if (!thr || (status == PR_FAILURE))
            {
                if (thr) 
                    delete thr;
                break;
            }
            threads_[i] = thr;
        }
    }

    if (i != this->numThreads_)
    {
        Freeup();
        return PR_FAILURE;
    }
    else
        return PR_SUCCESS;
}
Esempio n. 8
0
/*
 * Gets a name list of consisting of all ACL names for input list. 
 *
 * Input:
 *	acl_list	an ACL List handle	
 *	name_list	pointer to a list of string pointers	
 * Returns:
 *    0			success
 *    < 0		failure
 */
NSAPI_PUBLIC int
ACL_ListGetNameList(NSErr_t *errp, ACLListHandle_t *acl_list, char ***name_list)
{
    const int block_size = 50;
    ACLWrapper_t 	*wrapper;
    int			list_index;
    int			list_size;
    char		**tmp_list;
    char		**local_list;
    const char		*name;
    

    if ( acl_list == NULL )
        return(ACLERRUNDEF);

    list_size = block_size;
    local_list = (char **) PERM_MALLOC(sizeof(char *) * list_size);
    if ( local_list == NULL ) 
        return(ACLERRNOMEM); 
    list_index = 0;
    local_list[list_index] = NULL; 

    for ( wrapper = acl_list->acl_list_head; wrapper != NULL; 
                        wrapper = wrapper->wrap_next ) {
        if ( wrapper->acl->tag ) 
            name = wrapper->acl->tag;
        else 
            name = "noname";
        if ( list_index + 2 > list_size ) {
            list_size += block_size;
            tmp_list = (char **) PERM_REALLOC(local_list, 
                                              sizeof(char *) * list_size);
            if ( tmp_list == NULL ) {
                ACL_NameListDestroy(errp, local_list);
                return(ACLERRNOMEM); 
            }
            local_list = tmp_list;
        } 
        local_list[list_index] = PERM_STRDUP(name);
        if ( local_list[list_index] == NULL ) {
            ACL_NameListDestroy(errp, local_list);
            return(ACLERRNOMEM); 
        }
        list_index++;
        local_list[list_index] = NULL; 
    }    
    *name_list = local_list;
    return(0);
}
Esempio n. 9
0
NSAPI_PUBLIC FSMUTEX
fsmutex_init(char *name, int number, int flags)
{
    fsmutex_s *ret = (fsmutex_s *) PERM_MALLOC(sizeof(fsmutex_s));

    ret->flags = flags;
    if(_fsmutex_create(ret, name, number) == -1) {
        PERM_FREE(ret);
        return NULL;
    }
#ifdef THREAD_ANY
    if(flags & FSMUTEX_NEEDCRIT)
        ret->crit = crit_init();
#endif
    return (FSMUTEX) ret;
}
NSAPI_PUBLIC dns_cache_entry_t *
dns_cache_insert(char *host, unsigned int ip, unsigned int verified)
{
	dns_cache_entry_t *newentry;

	if ( !dns_cache || !ip)  {
		return NULL;
    }

	if ( (newentry = (dns_cache_entry_t *)PERM_MALLOC(sizeof(dns_cache_entry_t))) == NULL) {
		ereport(LOG_FAILURE, XP_GetAdminStr(DBT_dnsCacheInsertErrorAllocatingEnt_));
		goto error;
	}

	if (host) {
		if ( (newentry->host = PERM_STRDUP(host)) == NULL) {
			ereport(LOG_FAILURE, XP_GetAdminStr(DBT_dnsCacheInsertMallocFailure_));
			goto error;
		}
	} else
		newentry->host = NULL;

#ifdef CACHE_DEBUG
	newentry->cache.magic = CACHE_ENTRY_MAGIC;
#endif

	newentry->ip = ip;
	newentry->verified = verified;

	newentry->last_access = ft_time();

	if ( cache_insert_p(dns_cache, &(newentry->cache), (void *)&(newentry->ip), 
		(void *)newentry, &dns_cache_entry_functions) < 0) {
		/* Not a bad error; it just means the cache is full */
		goto error;
	}

	return newentry;

error:
	if (newentry) {
		if (newentry->host)
			PERM_FREE(newentry->host);
		PERM_FREE(newentry);
	}
	return NULL;
}
cache_entry_t *
cache_create_entry(void)
{
	cache_entry_t *newentry;

SOLARIS_PROBE(cache_create_entry_start, "cache");
	if ( (newentry = (cache_entry_t *)PERM_MALLOC(sizeof(cache_entry_t))) == NULL) {
		ereport(LOG_FAILURE, XP_GetAdminStr(DBT_unableToAllocateHashEntry_));
SOLARIS_PROBE(cache_create_entry_end, "cache");
		return NULL;
	}

#ifdef CACHE_DEBUG
	newentry->magic = CACHE_ENTRY_MAGIC;
#endif

SOLARIS_PROBE(cache_create_entry_end, "cache");
	return newentry;
}
Esempio n. 12
0
static Symbol_t *
acl_sym_new(ACLHandle_t *acl)
{
    Symbol_t *sym;
    /* It's not there, so add it */
    sym = (Symbol_t *) PERM_MALLOC(sizeof(Symbol_t));
    if ( sym == NULL ) 
        return(NULL);

    sym->sym_name = PERM_STRDUP(acl->tag);
    if ( sym->sym_name == NULL ) {
        PERM_FREE(sym);
        return(NULL);
    }

    sym->sym_type = ACLSYMACL;
    sym->sym_data = (void *) acl;
    return(sym);

}
/*
 *    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);
}
Esempio n. 14
0
/*
 *	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);
}
Esempio n. 15
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);

}
/** **************************************************************************
 * check-request-limits SAF
 *
 * See top of this file for the pb parameters this SAF can consume and the
 * defaults for each.
 *
 * This SAF counts requests per interval for the given monitor/bucket. If
 * the request/sec in an interval exceeds the max-rps given then it returns
 * REQ_ABORTED for this and all subsequent matching requests in the current
 * interval. After the next interval request rate recomputation the request
 * limiting may be discontinued if the conditions of 'continue' are met.
 *
 * Separately, concurrent requests for the same bucket may be limited to
 * the given number if max-connections is given.
 *
 * On the next request after purge_timeout, a purge sweep of the buckets is
 * done, deleting any entries which have not seen any recomputes in the 
 * purge interval (unless timeout disabled by setting it to zero).
 *
 * For more information, refer to the WS7.0 security functional spec at:
 * http://sac.eng/arc/WSARC/2004/076/
 *
 * For params: http://docs.sun.com/source/817-1835-10/npgmysaf.html#wp14889
 * For returns: http://docs.sun.com/source/817-1835-10/npgmysaf.html#wp14969
 *
 * This returns:
 *      REQ_NOACTION: If the request can go on.
 *      REQ_ABORTED: If the request has hit limits and is not to be processed.
 *          Return code is set to 'error' param (default 503).
 *
 */
int check_request_limits(pblock *pb, Session *sn, Request *rq)
{
    const char * param;
    int response = REQ_NOACTION;

    if (rq->rq_attr.req_restarted) {
        // Do not count restarted requests as new requests for the
        // purpose of reqlimit accounting as it is just one client
        // request.  (This is particularly important for
        // max-connections since processing restarts would cause the
        // conc counter to increase more than once for a given request
        // but only decrease once at the end).
        return response;
    }

    time_t time_now = rq->req_start;
    assert (time_now != NULL);

    // Get max-rps
    
    int max_rps = 0;
    param = pblock_findval(MAXRPS_PARAM, pb);
    if (param) {
        max_rps = atoi(param);
    }

    // Get max-connections

    int conc = 0;
    param = pblock_findval(CONC_PARAM, pb);
    if (param) {
        conc = atoi(param);
    }

    // We must have at least max-rps or max-connections, otherwise can't
    // do anything meaningful here

    if (!max_rps && !conc) {
        log_error(LOG_MISCONFIG, "check-request-limits", sn, rq,
                  XP_GetAdminStr(DBT_reqlimitCantWork));
        return response;
    }

    // Decide bucket name; if none, we use the anonymous bucket anon_bucket

    bucket_info * bucket = NULL;
    const char * bucket_name = pblock_findval(MONITOR_PARAM, pb);
    if (!bucket_name) {
        bucket = &anon_bucket;
    }

    // interval (in seconds), or use default

    int interval = DEFAULT_INTERVAL;
    param = pblock_findval(INTERVAL_PARAM, pb);
    if (param) {
        interval = atoi(param);
    }

    // Check continue, or use default
    int cont = DEFAULT_CONTINUE;
    param = pblock_findval(CONTINUE_PARAM, pb);
    if (param) {
        if (!strcmp(CONT_THRESHOLD_VAL, param)) { cont = CONT_THRESHOLD; }
        else if (!strcmp(CONT_SILENCE_VAL, param)) { cont = CONT_SILENCE; }
        else {
            // Log config error but continue since we have default
            log_error(LOG_MISCONFIG, "check-request-limits", sn, rq,
                      XP_GetAdminStr(DBT_reqlimitBadContinue));
        }
    }

    //----- START_CRIT ------------------------------

    crit_enter(reqlimit_crit);

    if (purge_timeout && (time_now > next_timeout)) { // run purge if needed
        handle_purge_timeout(time_now);
    }

    // If using anon bucket we already have reference to it, otherwise need
    // to go find it in hashtable (and if not found, create one)

    if (!bucket) {

        bucket = (bucket_info *)PL_HashTableLookup(hashtable, bucket_name);

        if (!bucket) {
            // Need to create new entry for this one
            log_error(LOG_VERBOSE, "check-request-limits", sn, rq,
                      "creating new entry for [%s]", bucket_name);
            bucket = (bucket_info *)PERM_MALLOC(sizeof(bucket_info));
            bucket->count = 1;
            bucket->time = time_now + interval;
            bucket->state = REQ_NOACTION;
            bucket->conc = 0;   // handle conc case on initial?
            PL_HashTableAdd(hashtable, 
                            (const void *)PERM_STRDUP(bucket_name), 
                            (void *)bucket);
            // Since it is the first request, no need to check more
            crit_exit(reqlimit_crit);
            return response;
        }
    }

    // If we are doing max-rps limiting then handle it otherwise don't bother

    if (max_rps) {

        bucket->count++;

        if (time_now > bucket->time) { 
            // Interval or more has passed, time to recompute and recheck

            int time_interval = time_now - bucket->time + interval;
            int rps = bucket->count / time_interval;

            log_error(LOG_VERBOSE, "check-request-limits", sn, rq,
                      "bucket [%s] %d req/s (%d req in %d sec)",
                      bucket_name ? bucket_name: "", 
                      rps, bucket->count, time_interval);

            if (rps > max_rps) {
                // Start limiting
                bucket->state = REQ_ABORTED;
                log_error(LOG_WARN,  "check-request-limits", sn, rq,
                          XP_GetAdminStr(DBT_reqlimitAboveMaxRPS),
                          rps, max_rps,
                          bucket_name ? bucket_name: "");

            } else {
                // Reset state if we're under threshhold or if this is first 
                // hit (which means an interval with zero hits has already 
                // passed)
                if ((cont == CONT_THRESHOLD) || (bucket->count == 1)) {
                    bucket->state = REQ_NOACTION;
                }
            }

            // Prepare for next interval by resetting count and recompute time
            bucket->count = 0;
            bucket->time = time_now + interval;
        }

        response = bucket->state;
    }

    // If decision to reject already done, no need to check or increase conc
    // since this is not getting processed anyway. Otherwise, do it if needed.
 
    if (conc && response != REQ_ABORTED) {

        if (bucket->conc >= conc) {
            // Note that this reject is based on conditions at this instant
            // instead of over an interval, so is independent of bucket->state
            response = REQ_ABORTED;

        } else {
            bucket->conc++;
            // This queues up a call to fn associated with req_cleanup
            // (here, reqlimit_conc_done) to be called after request is done
            request_set_data(rq, req_cleanup, bucket);
        }
    }

    crit_exit(reqlimit_crit);

    //----- END_CRIT ------------------------------

    if (response == REQ_NOACTION) {
        return REQ_NOACTION;
    }

    // abort this request

    int err = DEFAULT_ERROR;
    param = pblock_findval(ERROR_PARAM, pb);
    if (param) {
        err = atoi(param);
    }
    protocol_status(sn, rq, err, NULL);

    log_error(LOG_VERBOSE, "check-request-limits", sn, rq,
              "Rejecting request matching bucket [%s] with status %d",
              bucket_name ? bucket_name: "", err);
              
    return response;
}