/*
 * Copyright 2002 Lite Speed Technologies Inc, All Rights Reserved.
 * LITE SPEED PROPRIETARY/CONFIDENTIAL.
 */


#include <util/accesscontrol.h>
#include <util/accessdef.h>
#include <util/gpointerlist.h>
#include <util/stringtool.h>
#include <util/poolalloc.h>
#include <util/sysinfo/systeminfo.h>

#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>


int IPAccessControl::update(in_addr_t ip, long allow)
{
    iterator iter = GHash::find((void *)(unsigned long)ip);
    if (iter != end())
        iter.second()->setAccess(allow);
    else
    {
        AccessConfig *pConfig = new AccessConfig(allow);
        insert((void *)(unsigned long)ip, pConfig);
    }
    return 0;
}

void IPAccessControl::remove(in_addr_t ip)
{
    iterator iter = GHash::find((void *)(unsigned long)ip);
    if (iter != end())
    {
        delete iter.second();
        GHash::erase(iter);
    }
}


typedef union
{
    in6_addr    m_addr6;
    in_addr_t   m_addrs[4];
} Addr6;

static int isIPv6(const char *ip_mask)
{
    return (('[' == *ip_mask) || (strchr(ip_mask, ':')));
}

static int strToIPv6(char *ip, in6_addr *pAddr)
{
    if ('[' == *ip)
    {
        ++ip;
        char *pEnd = ip + strlen(ip) - 1 ;
        if (*pEnd != ']')
            return 0;
        *pEnd = 0;
    }
    return inet_pton(AF_INET6, ip, pAddr);
}


#include <util/pool.h>
#include "autostr.h"
#include "stringlist.h"

class IP6Acc
{
    in6_addr        m_addr;
    AccessConfig    m_config;
public:
    IP6Acc(const in6_addr &addr, int allow)
        : m_addr(addr)
        , m_config(allow)
    {}
    void setAccess(int allow)
    {   m_config.setAccess(allow);   }
    int getAccess() const
    {   return m_config.getAccess();   }
    const in6_addr &getAddr() const
    {   return m_addr;      }

    const AccessConfig *getAccessConf() const
    {   return &m_config;   }
    AccessConfig *getAccessConf()
    {   return &m_config;   }

    static hash_key_t hf(const void *pKey)
    {
        hash_key_t key;
        if (sizeof(hash_key_t) == 4)
        {
            key = *((const hash_key_t *)pKey) +
                  *(((const hash_key_t *)pKey) + 1) +
                  *(((const hash_key_t *)pKey) + 2) +
                  *(((const hash_key_t *)pKey) + 3);
        }
        else
        {
            key = *((const hash_key_t *)pKey) +
                  *(((const hash_key_t *)pKey) + 1);
        }
        return key;
    }

    static int  cmp(const void *pVal1, const void *pVal2)
    {
        return memcmp(pVal1, pVal2, 16);
    }

};



class IP6AccessControl : public THash< IP6Acc * >
{
    typedef THash< IP6Acc * > IP6Hash;
public:
    explicit IP6AccessControl(int initSize)
        : IP6Hash(initSize, IP6Acc::hf, IP6Acc::cmp)
    {}

    ~IP6AccessControl() { release_objects();  };

    int addUpdate(const in6_addr &ip, long allow);

    void remove(const in6_addr &ip)
    {
        IP6Hash::iterator iter = IP6Hash::find(&ip);
        if (iter != end())
        {
            delete iter.second();
            IP6Hash::erase(iter);
        }
    }
    void clear()    {   release_objects(); IP6Hash::clear();  }
    size_t size() const {   return IP6Hash::size();   }
};



int IP6AccessControl::addUpdate(const in6_addr &ip, long allow)
{
    iterator iter = find(&ip);
    if (iter == end())
    {
        IP6Acc *pAcc = new IP6Acc(ip, allow);
        if (pAcc)
            insert(&pAcc->getAddr(), pAcc);

    }
    else
        iter.second()->setAccess(allow);
    return 0;
}




class SubNetNode
{
    typedef TPointerList<SubNetNode> NodeList;
    NodeList  m_children;
    in_addr_t m_id;
    in_addr_t m_mask;
    AccessConfig m_config;
public:
    SubNetNode(in_addr_t id, in_addr_t mask, int allowed)
        : m_id(id), m_mask(mask), m_config(allowed)
    {}
    ~SubNetNode();

    int hasAccess() const           {   return m_config.getAccess();   }
    unsigned int getId() const      {   return m_id;        }
    const in_addr_t &getMask() const {   return m_mask;      }
    void setMask(in_addr_t mask)  {   m_mask = mask;      }
    void setAccess(int allow)       {   m_config.setAccess(allow); }

    const AccessConfig *getAccessConf() const
    {   return &m_config;   }
    AccessConfig *getAccessConf()
    {   return &m_config;   }

    SubNetNode *insertChild(in_addr_t ip, in_addr_t mask, int allowed);
    SubNetNode *insertChild(SubNetNode *pNode);
    SubNetNode *matchNode(in_addr_t ip);
    void clear();

    void *operator new(size_t sz)
    {   return g_pool.allocate(sizeof(SubNetNode));   }
    void operator delete(void *p)
    {   return g_pool.deallocate(p, sizeof(SubNetNode));    }
};

SubNetNode::~SubNetNode()
{
    clear();
}

void SubNetNode::clear()
{
    NodeList::iterator iter;
    for (iter = m_children.begin(); iter != m_children.end(); ++iter)
        delete *iter;
    m_children.clear();
}

SubNetNode *SubNetNode::insertChild(in_addr_t ip, in_addr_t mask,
                                    int allowed)
{
    in_addr_t id = ip & mask ;
    SubNetNode *pNewChild = new SubNetNode(id, mask, allowed);
    return insertChild(pNewChild);

}

SubNetNode *SubNetNode::insertChild(SubNetNode *pNode)
{
    //new( pNewChild )

    // the newly inserted one may be parent of other siblings

    NodeList::iterator iter;
    for (iter = m_children.begin(); iter != m_children.end();)
    {
        if (((*iter)->m_id & pNode->m_mask) == pNode->m_id)
        {
            if ((*iter)->m_mask == pNode->m_mask)
            {
                (*iter)->m_config.setAccess(pNode->m_config.getAccess());
                delete pNode;
                return *iter;
            }
            else if (((*iter)->m_mask & pNode->m_mask) == pNode->m_mask)
            {
                pNode->m_children.push_back(*iter);
                m_children.erase(iter);
            }
            else
                return (*iter)->insertChild(pNode);
        }
        else if ((pNode->m_id & (*iter)->m_mask) == (*iter)->m_id)
            return (*iter)->insertChild(pNode);
        else
            ++iter;
    }

    m_children.push_back(pNode);

    return pNode;
}

SubNetNode *SubNetNode::matchNode(in_addr_t ip)
{
    NodeList::const_iterator pos;

    NodeList::const_iterator pEnd = m_children.end();
    for (pos = m_children.begin(); pos != pEnd ; ++pos)
    {
        if ((ip & (*pos)->m_mask) == (*pos)->m_id)
            return *pos;
    }
    return NULL;
}



class SubNet6Node
{
    typedef TPointerList<SubNet6Node> NodeList;
    NodeList  m_children;
    Addr6     m_id;
    Addr6     m_mask;
    AccessConfig m_config;
public:
    SubNet6Node(const in6_addr &id, const in6_addr &mask, int allowed)
        : m_config(allowed)
    {
        m_id.m_addr6 = id;
        m_mask.m_addr6 = mask;
    }
    ~SubNet6Node();

    void andMask(Addr6 &dest, const Addr6 &ip, const Addr6 &mask)
    {
        dest.m_addrs[0] = ip.m_addrs[0] & mask.m_addrs[0];
        dest.m_addrs[1] = ip.m_addrs[1] & mask.m_addrs[1];
        dest.m_addrs[2] = ip.m_addrs[2] & mask.m_addrs[2];
        dest.m_addrs[3] = ip.m_addrs[3] & mask.m_addrs[3];
    }
    int hasAccess() const           {   return m_config.getAccess();   }
    const Addr6 &getId() const      {   return m_id;        }
    const Addr6 &getMask() const    {   return m_mask;      }
    void setMask(in6_addr &mask)  {   m_mask.m_addr6 = mask;      }
    void setAccess(int allow)       {   m_config.setAccess(allow); }

    const AccessConfig *getAccessConf() const
    {   return &m_config;   }
    AccessConfig *getAccessConf()
    {   return &m_config;   }

    SubNet6Node *insertChild(const in6_addr &ip, const in6_addr &mask,
                             int allowed);
    SubNet6Node *insertChild(SubNet6Node *pNode);
    SubNet6Node *matchNode(const in6_addr &ip);
    void clear();

    void *operator new(size_t sz)
    {   return g_pool.allocate(sizeof(SubNet6Node));   }
    void operator delete(void *p)
    {   return g_pool.deallocate(p, sizeof(SubNet6Node));    }
};

SubNet6Node::~SubNet6Node()
{
    clear();
}

void SubNet6Node::clear()
{
    NodeList::iterator iter;
    for (iter = m_children.begin(); iter != m_children.end(); ++iter)
        delete *iter;
    m_children.clear();
}

SubNet6Node *SubNet6Node::insertChild(const in6_addr &ip,
                                      const in6_addr &mask, int allowed)
{
    Addr6 id;
    andMask(id, (const Addr6 &)ip, (const Addr6 &)mask);
    SubNet6Node *pNewChild = new SubNet6Node(id.m_addr6, mask, allowed);
    return insertChild(pNewChild);

}

SubNet6Node *SubNet6Node::insertChild(SubNet6Node *pNode)
{

    // the newly inserted one may be parent of other siblings
    NodeList::iterator iter;
    for (iter = m_children.begin(); iter != m_children.end();)
    {
        Addr6 id1;
        andMask(id1, (*iter)->m_id, (const Addr6 &)pNode->m_mask);
        if (GHash::cmp_ipv6(&id1, &pNode->m_id) == 0)
        {
            if (GHash::cmp_ipv6(&(*iter)->m_mask, &pNode->m_mask) == 0)
            {
                (*iter)->setAccess(pNode->getAccessConf()->getAccess());
                delete pNode;
                return *iter;
            }
            else
            {
                pNode->m_children.push_back(*iter);
                m_children.erase(iter);
            }
        }
        else
        {
            Addr6 id2;
            andMask(id2, pNode->m_id, (const Addr6 &)((*iter)->m_mask));
            if (GHash::cmp_ipv6(&id2, &(*iter)->m_id) == 0)
                return (*iter)->insertChild(pNode);
            else
                ++iter;
        }
    }

    m_children.push_back(pNode);

    return pNode;
}

SubNet6Node *SubNet6Node::matchNode(const in6_addr &ip)
{
    NodeList::const_iterator pos;

    NodeList::const_iterator pEnd = m_children.end();
    for (pos = m_children.begin(); pos != pEnd ; ++pos)
    {
        Addr6 id;
        andMask(id, (const Addr6 &)ip, (*pos)->m_mask);
        if (GHash::cmp_ipv6(&id, &(*pos)->m_id) == 0)
            return *pos;
    }
    return NULL;
}




AccessControl::AccessControl()
    : m_ipCtrl(13)
    , m_pIp6Ctrl(NULL)
    , m_pEnvRules(NULL)
{
    m_pRoot = new SubNetNode(0, 0, true);
    in6_addr addr;
    memset(&addr, 0, sizeof(addr));
    m_pRoot6 = new SubNet6Node(addr, addr, true);
}
AccessControl::~AccessControl()
{
    delete m_pRoot ;
    delete m_pRoot6 ;
    if (m_pIp6Ctrl)
        delete m_pIp6Ctrl;
    if (m_pEnvRules)
        delete m_pEnvRules;
}

const AccessConfig *AccessControl::getAccessConf(in_addr_t ip) const
{
    if (m_ipCtrl.size())
    {
        const AccessConfig *pConf = m_ipCtrl.find(ip);
        if (pConf)
            return pConf;
    }

    SubNetNode *pCurNode = m_pRoot ;
    SubNetNode *pNextNode;

    while ((pNextNode = pCurNode->matchNode(ip)) != NULL)
        pCurNode = pNextNode;

    return pCurNode->getAccessConf();

}
const AccessConfig *AccessControl::getAccessConf(const in6_addr &ip) const
{
    if (m_pIp6Ctrl)
    {
        IP6AccessControl::iterator iter = m_pIp6Ctrl->find(&ip);
        if (iter != m_pIp6Ctrl->end())
            return iter.second()->getAccessConf();
    }
    SubNet6Node *pCurNode = m_pRoot6 ;
    SubNet6Node *pNextNode;

    while ((pNextNode = pCurNode->matchNode(ip)) != NULL)
        pCurNode = pNextNode;

    return pCurNode->getAccessConf();

}

const AccessConfig *AccessControl::getAccessConf(const struct sockaddr
        *pAddr) const
{
    switch (pAddr->sa_family)
    {
    case AF_INET:
        return getAccessConf((((const sockaddr_in *)pAddr)->sin_addr).s_addr);
    case AF_INET6:
        return getAccessConf(((const sockaddr_in6 *)pAddr)->sin6_addr);
    case AF_UNSPEC:
    case AF_UNIX:
    default:
        break;
    }
    return NULL;

}

const AccessConfig *AccessControl::getAccessConf(const char *pchIP) const
{
    if (!isIPv6(pchIP))
    {
        in_addr ip;
        if (0 >= inet_pton(AF_INET, pchIP, &ip))
            return NULL ; //err in conversion
        return getAccessConf(ip.s_addr);
    }
    else
    {
        char achTemp[128];
        memccpy(achTemp, pchIP, 0, 127);
        achTemp[127] = 0;
        in6_addr ip;
        if (0 >= strToIPv6(achTemp, &ip))
            return NULL;
        return getAccessConf(ip);
    }

}

static int checkTrust(char *ip_mask, int allowed)
{
    int len = strlen(ip_mask);
    char ch = *(ip_mask + len - 1);
    if ((ch == 't') || (ch == 'T'))
    {
        if (allowed)
            allowed = AC_TRUST;
        *(ip_mask + len - 1) = 0;
    }
    return allowed;
}


int AccessControl::addIPControl(const char *pchIP, int allowed)
{
    char achTemp[128];
    memccpy(achTemp, pchIP, 0, 127);
    achTemp[127] = 0;
    allowed = checkTrust(achTemp, allowed);
    if (!isIPv6(achTemp))
    {
        in_addr ip;
        if (0 >= inet_pton(AF_INET, achTemp, &ip))
            return -1 ; //err in conversion
        return addIPControl(ip.s_addr, allowed);
    }
    else
    {
        in6_addr ip;
        if (0 >= strToIPv6(achTemp, &ip))
            return false;
        return addIPControl(ip, allowed);
    }
}


void AccessControl::removeIPControl(const char *pchIP)
{
    if (!isIPv6(pchIP))
    {
        in_addr ip;
        if (0 >= inet_pton(AF_INET, pchIP, &ip))
            return ; //err in conversion
        return removeIPControl(ip.s_addr);
    }
    else
    {
        char achTemp[128];
        memccpy(achTemp, pchIP, 0, 127);
        achTemp[127] = 0;
        in6_addr ip;
        if (0 >= strToIPv6(achTemp, &ip))
            return;
        if (IN6_IS_ADDR_V4MAPPED(&ip))
            return removeIPControl(((Addr6 *)&ip)->m_addrs[3]);
        if (m_pIp6Ctrl)
            return m_pIp6Ctrl->remove(ip);
    }
}

int AccessControl::addSubNetControl(in_addr_t subNet,
                                    in_addr_t mask,
                                    int allowed)
{
    if (mask == 0xffffffff)
        return addIPControl(subNet, allowed);
    if (mask == 0)
    {
        m_pRoot->setAccess(allowed);
        return 0;
    }

    return insSubNetControl(subNet, mask, allowed);
}

int AccessControl::insSubNetControl(in_addr_t subNet,
                                    in_addr_t mask,
                                    int allowed)
{
    SubNetNode *pCur = m_pRoot;
    //SubNetNode* pNext;
    /*
        while ( ( pNext = pCur->matchNode( subNet ) ) != NULL )
        {
            if ( pNext->getMask() == mask )
            {
                pNext->setAccess( allowed );
                return 1; // confict with previous
            }
            pCur = pNext ;
        }
    */

    pCur->insertChild(subNet, mask, allowed);
    return 0;
}

static unsigned char s_maskbits[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
int AccessControl::parseNetmask(const char *netMask, int maxbits,
                                void *pMask)
{
    char *pEnd;
    if (!isdigit(*netMask))
        return -1;
    int bits = strtol(netMask, &pEnd, 10);
    if ((*pEnd == 0) && (bits >= 0) && (bits < maxbits))
    {
        memset(pMask, 0xff, bits / 8);
        memset(((char *)pMask) + (bits + 7) / 8, 0, (maxbits - bits) / 8);
        if (bits % 8)
            *(((char *)pMask) + bits / 8) = s_maskbits[ bits % 8 ];
        return 0;
    }
    else
        return ((maxbits != 32) || (0 >= inet_pton(AF_INET, netMask, pMask)));


}

int AccessControl::addSubNetControl(const char *ip, const char *netMask,
                                    int allowed)
{
    //FIXME:no validation of string
    if (!isIPv6(ip))
    {
        in_addr subNet, mask;
        if (0 >= inet_pton(AF_INET, ip, &subNet))
            return -1;
        if (0 != parseNetmask(netMask, 32, &mask))
            return -1;
        return addSubNetControl(subNet.s_addr, mask.s_addr, allowed);
    }
    in6_addr addr, mask;
    char achTemp[128];
    memccpy(achTemp, ip, 0, 127);
    achTemp[127] = 0;
    if (0 >= strToIPv6(achTemp, &addr))
        return -1;
    if (0 != parseNetmask(netMask, 128, &mask))
        return -1;
    return addSubNetControl(addr, mask, allowed);
}

int AccessControl::addIPv4(const char *ip_mask, int allowed)
{
    char ip[256], mask[256];
    const char *p0 ;

    mask[0] = 0;
    p0 = (char *)strchr(ip_mask, '*');
    if (p0 == NULL)
        p0 = (char *)ip_mask + strlen(ip_mask) + 1;
    if (p0 <= ip_mask)
        return 0;
    memccpy(ip, ip_mask, 0, p0 - ip_mask);
    ip[p0 - ip_mask - 1] = 0;

    int c = 0;
    p0 = (char *)ip_mask;
    while (*p0)
    {
        if (*p0 == '.')
            ++c;
        else if (*p0 == '*')
            break;
        ++p0;
    }
    if (*p0 != '*')
        ++c;
    if (c == 4)
        return addIPControl(ip, allowed);
    int i = 0 ;
    for (; i < c ; ++ i)
    {
        if (i == 0)
            strcat(mask, "255");
        else
            strcat(mask, ".255");
    }
    for (i = 0 ; i < 4 - c ; ++ i)
    {
        strcat(ip, ".0");
        strcat(mask, ".0");
    }
    in_addr subNet, netmask;
    if (0 >= inet_pton(AF_INET, ip, &subNet))
        return -1;
    if (0 >= inet_pton(AF_INET, mask, &netmask))
        return -1;

    return addSubNetControl(subNet.s_addr, netmask.s_addr, allowed);
}


int AccessControl::addSubNetControl(const char *ip_mask, int allowed)
{
    //IPv4 formats: "192.168.1.*", "192.168.128.5/255.255.128.0", "192.168.128", "192.168.128.0/24"
    //IPv6: "::", "::1", "[::1]", "fdab:78a3:3487::1/120"
    const char *p0 ;
    char ip[256], mask[256];
    char achTemp[128];
    memccpy(achTemp, ip_mask, 0, 127);
    achTemp[127] = 0;
    allowed = checkTrust(achTemp, allowed);
    ip_mask = achTemp;
    p0 = (char *)strchr(ip_mask, '/');
    if (p0 != NULL)
    {
        memccpy(ip, ip_mask, 0, p0 - ip_mask);
        ip[p0 - ip_mask] = 0;
        strcpy(mask, p0 + 1);
        return addSubNetControl(ip, mask, allowed);
    }
    if ((strcmp(ip_mask, "*") == 0) || (strcasecmp(ip_mask, "ALL") == 0))
    {
        m_pRoot->setAccess(allowed);
        m_pRoot6->setAccess(allowed);
        return 0;
    }
    else
    {
        if (!isIPv6(achTemp))
            return addIPv4(achTemp, allowed);
        else
            return addIPControl(achTemp, allowed);
    }

}

void AccessControl::clear()
{
    m_pRoot->clear();
    m_pRoot6->clear();
    m_ipCtrl.clear();
}


int AccessControl::addList(const char *pList, int allow)
{
    return addList(pList, strlen(pList), allow);
}

int AccessControl::addList(const char *pList, int size, int allow)
{
    char achBuf[4096];
    int added = 0;
    const char *pListEnd = pList + size;
    const char *pEnd;
    const char *p;
    while (pList)
    {
        while (isspace(*pList) && pList < pListEnd)
            ++pList;
        if (pList >= pListEnd)
            break;
        if (*pList == '#')
        {
            p = (const char *)memchr(pList, '\n', pListEnd - pList);
            if (p)
                pList = ++p;
            else
                break;
            continue;
        }
        p = StringTool::mempbrk(pList, pListEnd - pList, ", \r\n", 4);
        if (p)
            pEnd = p++;
        else
            pEnd = pListEnd;
        int len = StringTool::strtrim(pList, pEnd);
        if ((len > 0) && (len < (int)sizeof(achBuf)))
        {
            memccpy(achBuf, pList, 0, len);
            achBuf[len] = 0;
            //if ( strchr( achBuf, '*' )||( strchr( achBuf, '/' ))
            //    || (achBuf[len-1] == '.' )
            //    || (strcasecmp( achBuf, "ALL") == 0 ))
            if (strncasecmp(achBuf, "env=", 4) == 0)
                addEnvRule(&achBuf[4], len - 4, allow);
            else
            {
                if (achBuf[len - 1] == '.')
                    achBuf[len - 1] = 0;
                added += (addSubNetControl(achBuf, allow) == 0);
            }
            //else
            //    added += ( addIPControl( achBuf, allow ) == 0 );

        }
        pList = p;
    }
    return added;
}


int AccessControl::addIPControl(const in6_addr &ip, int allowed)
{
    if (IN6_IS_ADDR_V4MAPPED(&ip))
        return addIPControl(((Addr6 *)&ip)->m_addrs[3], allowed);
    Addr6 *p = (Addr6 *)&ip;
    if ((!p->m_addrs[0]) && (!p->m_addrs[1]) && (!p->m_addrs[2])
        && (!p->m_addrs[3]))
    {
        m_pRoot6->setAccess(allowed);
        return 0;
    }
    if (!m_pIp6Ctrl)
        m_pIp6Ctrl = new IP6AccessControl(13);
    if (m_pIp6Ctrl)
        return m_pIp6Ctrl->addUpdate(ip, allowed);
    return -1;
}



int AccessControl::addSubNetControl(const in6_addr &subNet,
                                    const in6_addr &mask,
                                    int allowed)
{
    Addr6 *p = (Addr6 *)&mask;
    if (IN6_IS_ADDR_V4MAPPED(&subNet))
    {
        if (p->m_addrs[3])
            return addSubNetControl(((Addr6 *)&subNet)->m_addrs[3], p->m_addrs[3],
                                    allowed);
        return -1;
    }
    if ((0xffffffff == p->m_addrs[3]) &&
        (0xffffffff == p->m_addrs[2]) &&
        (0xffffffff == p->m_addrs[1]) &&
        (0xffffffff == p->m_addrs[0]))
        return addIPControl(subNet, allowed);
    if ((!p->m_addrs[0]) && (!p->m_addrs[1]) && (!p->m_addrs[2])
        && (!p->m_addrs[3]))
    {
        m_pRoot6->setAccess(allowed);
        return 0;
    }

    return insSubNetControl(subNet, mask, allowed);
}

int AccessControl::insSubNetControl(const in6_addr &subNet,
                                    const in6_addr &mask,
                                    int allowed)
{
    SubNet6Node *pCur = m_pRoot6;
    SubNet6Node *pNext;
    while ((pNext = pCur->matchNode(subNet)) != NULL)
    {
        if (GHash::cmp_ipv6(&pNext->getMask(), &mask) == 0)
        {
            pNext->setAccess(allowed);
            return 1; // confict with previous
        }
        pCur = pNext ;
    }

    pCur->insertChild(subNet, mask, allowed);
    return 0;
}

void AccessControl::addBandControl(char *pBegin, int len, int band)
{
    AccessConfig *pAC = (AccessConfig *)getAccessConf(pBegin);
    if (!pAC)
    {
        addList(pBegin, len, AC_ALLOW);
        pAC = (AccessConfig *)getAccessConf(pBegin);
    }
    if (!pAC)
        return;
    pAC->setBandwidth(band);
}


int AccessControl::addEnvRule(const char *pEnv, int len, int allow)
{
    if (!m_pEnvRules)
        m_pEnvRules = new StringList();
    AutoStr2 *pRule;
    pRule = new AutoStr2();
    pRule->prealloc(len + 2);
    if (allow)
        *pRule->buf() = 1;
    else
        *pRule->buf() = -1;
    memcpy(pRule->buf() + 1, pEnv, len);
    *(pRule->buf() + 1 + len) = 0;
    pRule->setLen(len + 1);
    m_pEnvRules->push_back(pRule);
    return 0;
}


int AccessControl::getDefault() const
{
    if (m_pRoot)
        return m_pRoot->hasAccess();
    else
        return 1;
}


