Пример #1
0
    def PwDecrypt(self, password):
        """Unobfuscate a RADIUS password. RADIUS hides passwords in packets by
        using an algorithm based on the MD5 hash of the packet authenticator
        and RADIUS secret. This function reverses the obfuscation process.

        :param password: obfuscated form of password
        :type password:  binary string
        :return:         plaintext password
        :rtype:          unicode string
        """
        buf = password
        pw = six.b('')

        last = self.authenticator
        while buf:
            hash = md5_constructor(self.secret + last).digest()
            if six.PY3:
                for i in range(16):
                    pw += bytes((hash[i] ^ buf[i], ))
            else:
                for i in range(16):
                    pw += chr(ord(hash[i]) ^ ord(buf[i]))

            (last, buf) = (buf[:16], buf[16:])

        while pw.endswith(six.b('\x00')):
            pw = pw[:-1]

        return pw.decode('utf-8')
Пример #2
0
 def __init__(self,
              code=AccountingRequest,
              id=None,
              secret=six.b(''),
              authenticator=None,
              **attributes):
     AcctPacket.__init__(self, code, id, six.b(secret), authenticator,
                         **attributes)
     ExtAttrMixin.__init__(self)
Пример #3
0
def get_dm_packet(vendor_id, nas_secret, nas_addr, coa_port=3799, **kwargs):
    coa_request = message.CoAMessage(code=packet.DisconnectRequest,
                                     dict=RADIUS_DICT,
                                     secret=six.b(str(nas_secret)),
                                     **kwargs)
    username = coa_request["User-Name"][0]
    if int(vendor_id) == ikuai.VENDOR_ID:
        pkg = ikuai.create_dm_pkg(six.b(str(nas_secret)), username)
        return (pkg, nas_addr, coa_port)
    else:
        return (coa_request.RequestPacket(), nas_addr, coa_port)
Пример #4
0
    def _PktEncodeAttributes(self):
        result = six.b('')
        for (code, datalst) in self.items():
            for data in datalst:
                result += self._PktEncodeAttribute(code, data)

        return result
Пример #5
0
    def PwDecrypt(self, password):
        buf = password
        pw = six.b('')

        last = self.authenticator
        while buf:
            hash = md5_constructor(self.secret + last).digest()
            for i in range(16):
                pw += chr(ord(hash[i]) ^ ord(buf[i]))

            (last, buf) = (buf[:16], buf[16:])

        while pw.endswith(six.b('\x00')):
            pw = pw[:-1]

        return pw.decode('utf-8')
Пример #6
0
def send_auth(server,
              port=1812,
              secret=six.b("testing123"),
              debug=False,
              dictfile=None,
              **kwargs):
    """
    send auth request

    :param server: radius server ipaddr
    :param port: auth port, default 1812

    :param secret: nas share secret
    :param debug: logging level

    :param dictfile: dictionary file path
    :param kwargs: request params

    :return: auth response
    """
    try:
        radius_dictionary = get_dictionary(dictfile=dictfile)
        timeout_sec = kwargs.pop('timeout', 5)
        result = kwargs.pop('result', True)
        User_Password = kwargs.pop("User-Password", None)
        CHAP_Password = kwargs.pop("CHAP-Password", None)
        CHAP_Password_Plaintext = kwargs.pop("CHAP-Password-Plaintext", None)
        CHAP_Challenge = kwargs.get("CHAP-Challenge")
        request = message.AuthMessage(dict=radius_dictionary,
                                      secret=secret,
                                      **kwargs)
        if User_Password:
            request['User-Password'] = request.PwCrypt(User_Password)
        if CHAP_Password:
            if CHAP_Challenge:
                request['CHAP-Challenge'] = CHAP_Challenge
            request['CHAP-Password'] = CHAP_Password
        if CHAP_Password_Plaintext:
            request['CHAP-Password'] = request.ChapEcrypt(
                CHAP_Password_Plaintext)

        if debug:
            logger.debug("Send radius auth request to (%s:%s): %s" %
                         (server, port, request.format_str()))

        sock = socket.socket(type=socket.SOCK_DGRAM)
        sock.settimeout(timeout_sec)
        sock.connect((server, port))
        sock.send(request.RequestPacket())
        if result:
            data, address = sock.recvfrom(8192)
            reply = request.CreateReply(packet=data)
            if debug:
                logger.debug("Recv radius auth response from (%s:%s): %s" %
                             (server, port, reply.format_str()))
            return reply
    except Exception as e:
        logger.error("authenticator error {}".format(e.message), exc_info=True)
Пример #7
0
 def VerifyCoARequest(self):
     """Verify request authenticator.
     :return: True if verification failed else False
     :rtype: boolean
     """
     # assert(self.raw_packet)
     hash = md5_constructor(self.raw_packet[0:4] + 16 * six.b('\x00') +
                            self.raw_packet[20:] + self.secret).digest()
     return hash == self.authenticator
Пример #8
0
    def PwCrypt(self, password):
        """Obfuscate password.
        RADIUS hides passwords in packets by using an algorithm
        based on the MD5 hash of the packet authenticator and RADIUS
        secret. If no authenticator has been set before calling PwCrypt
        one is created automatically. Changing the authenticator after
        setting a password that has been encrypted using this function
        will not work.

        :param password: plaintext password
        :type password:  unicode stringn
        :return:         obfuscated version of the password
        :rtype:          binary string
        """
        if self.authenticator is None:
            self.authenticator = self.CreateAuthenticator()

        if isinstance(password, six.text_type):
            password = password.encode('utf-8')

        buf = password
        if len(password) % 16 != 0:
            buf += six.b('\x00') * (16 - (len(password) % 16))

        hash = md5_constructor(self.secret + self.authenticator).digest()
        result = six.b('')

        last = self.authenticator
        while buf:
            hash = md5_constructor(self.secret + last).digest()
            if six.PY3:
                for i in range(16):
                    result += bytes((hash[i] ^ buf[i], ))
            else:
                for i in range(16):
                    result += chr(ord(hash[i]) ^ ord(buf[i]))

            last = result[-16:]
            buf = buf[16:]

        return result
Пример #9
0
 def __init__(self,
              vendor_id,
              dictionary,
              nas_secret,
              nas_addr,
              coa_port=3799,
              debug=False):
     self.dictionary = dictionary
     self.secret = six.b(str(nas_secret))
     self.addr = nas_addr
     self.port = int(coa_port)
     self.vendor_id = int(vendor_id)
     self.debug = debug
     self.uport = reactor.listenUDP(0, self)
Пример #10
0
 def __init__(self,
              secret,
              dictionary,
              server,
              authport=1812,
              acctport=1813,
              debug=False):
     self.dict = dictionary
     self.secret = six.b(secret)
     self.server = server
     self.authport = authport
     self.acctport = acctport
     self.debug = debug
     reactor.listenUDP(0, self)
Пример #11
0
    def PwCrypt(self, password):
        if self.authenticator is None:
            self.authenticator = self.CreateAuthenticator()

        if isinstance(password, six.text_type):
            password = password.encode('utf-8')

        buf = password
        if len(password) % 16 != 0:
            buf += six.b('\x00') * (16 - (len(password) % 16))

        hash = md5_constructor(self.secret + self.authenticator).digest()
        result = six.b('')

        last = self.authenticator
        while buf:
            hash = md5_constructor(self.secret + last).digest()
            for i in range(16):
                result += chr(ord(hash[i]) ^ ord(buf[i]))

            last = result[-16:]
            buf = buf[16:]

        return result
Пример #12
0
    def RequestPacket(self):
        """Create a ready-to-transmit CoA request packet.
        Return a RADIUS packet which can be directly transmitted
        to a RADIUS server.
        :return: raw packet
        :rtype:  string
        """

        attr = self._PktEncodeAttributes()

        if self.id is None:
            self.id = self.CreateID()

        header = struct.pack('!BBH', self.code, self.id, (20 + len(attr)))
        self.authenticator = md5_constructor(header[0:4] + 16 * six.b('\x00') +
                                             attr + self.secret).digest()
        return header + self.authenticator + attr
Пример #13
0
 def __init__(self, code=CoARequest, id=None, secret=six.b(''),
         authenticator=None, **attributes):
     """Constructor
     :param dict:   RADIUS dictionary
     :type dict:    pyrad.dictionary.Dictionary class
     :param secret: secret needed to communicate with a RADIUS server
     :type secret:  string
     :param id:     packet identifaction number
     :type id:      integer (8 bits)
     :param code:   packet type code
     :type code:    integer (8bits)
     :param packet: raw packet to decode
     :type packet:  string
     """
     Packet.__init__(self, code, id, secret, authenticator, **attributes)
     if 'packet' in attributes:
         self.raw_packet = attributes['packet']
Пример #14
0
    def __init__(self,
                 code=0,
                 id=None,
                 secret=six.b(''),
                 authenticator=None,
                 **attributes):
        """Constructor

        :param dict:   RADIUS dictionary
        :type dict:    pyrad.dictionary.Dictionary class
        :param secret: secret needed to communicate with a RADIUS server
        :type secret:  string
        :param id:     packet identifaction number
        :type id:      integer (8 bits)
        :param code:   packet type code
        :type code:    integer (8bits)
        :param packet: raw packet to decode
        :type packet:  string
        """
        dict.__init__(self)
        self.code = code
        if id is not None:
            self.id = id
        else:
            self.id = CreateID()
        if not isinstance(secret, six.binary_type):
            raise TypeError('secret must be a binary string')
        self.secret = secret
        if authenticator is not None and \
                not isinstance(authenticator, six.binary_type):
            raise TypeError('authenticator must be a binary string')
        self.authenticator = authenticator

        if 'dict' in attributes:
            self.dict = attributes['dict']

        if 'packet' in attributes:
            self.DecodePacket(attributes['packet'])

        for (key, value) in attributes.items():
            if key in ['dict', 'fd', 'packet']:
                continue
            key = key.replace('_', '-')
            self.AddAttribute(key, value)
Пример #15
0
def send_acct(server,
              port=1813,
              secret=six.b("testing123"),
              debug=False,
              dictfile=None,
              **kwargs):
    """
    send accounting request

    :param server: radius server ipaddr
    :param port: acct port, default 1813

    :param secret: nas share secret
    :param debug: logging level

    :param dictfile: dictionary file path
    :param kwargs: request params

    :return: acct response
    """
    try:
        radius_dictionary = get_dictionary(dictfile=dictfile)
        timeout_sec = kwargs.pop('timeout', 5)
        result = kwargs.pop('result', True)
        request = message.AcctMessage(dict=radius_dictionary,
                                      secret=secret,
                                      **kwargs)
        if debug:
            logger.debug("Send radius acct request to (%s:%s): %s" %
                         (server, port, request.format_str()))

        sock = socket.socket(type=socket.SOCK_DGRAM)
        sock.settimeout(timeout_sec)
        sock.connect((server, port))
        sock.send(request.RequestPacket())
        if result:
            data, address = sock.recvfrom(8192)
            reply = request.CreateReply(packet=data)
            if debug:
                logger.debug("Recv radius auth response from (%s:%s): %s" %
                             (server, port, reply.format_str()))
            return reply
    except Exception as e:
        logger.error("accounting error {}".format(e.message), exc_info=True)
Пример #16
0
Acct_Status_Off = 8

def parse_auth_packet(datagram,(host,port),client_config,dictionary=None):
    """
    parse radius auth request
    :param datagram:
    :param client_config:
    :param dictionary:
    :return:
    """
    if host in client_config.defaults:
        client = client_config.defaults[host]
        authreq = message.AuthMessage(packet=datagram, dict=dictionary,secret=str(client['secret']))
        authreq.vendor_id=client_config.vendors.get(client['vendor'])
    else:
        authreq = message.AuthMessage(packet=datagram,dict=dictionary, secret=six.b(''))
        nas_id = authreq.get_nas_id()
        _client = [c for c in client_config.defaults.itervalues() if c['nasid'] == nas_id]
        if _client:
            client = _client[0]
            authreq.vendor_id = client_config.vendors.get(client['vendor'])
            authreq.secret = six.b(client['secret'])
        else:
            raise packet.PacketError("Unauthorized Radius Access Device [%s] (%s:%s)"%(nas_id,host,port))

    authreq.source = (host,port)
    authreq = request_logger.handle_radius(authreq)
    authreq = request_mac_parse.handle_radius(authreq)
    authreq = request_vlan_parse.handle_radius(authreq)

    return authreq
Пример #17
0
class BasicAdapter(object):
    def __init__(self, settings):
        self.settings = settings
        self.pool = Pool(self.settings.RADIUSD['pool_size'])
        self.logger = logging.getLogger(__name__)
        self.dictionary = dictionary.Dictionary(
            self.settings.RADIUSD['dictionary'])
        self.auth_pre = [
            importlib.import_module(m)
            for m in self.settings.MODULES["auth_pre"]
        ]
        self.acct_pre = [
            importlib.import_module(m)
            for m in self.settings.MODULES["acct_pre"]
        ]
        self.auth_post = [
            importlib.import_module(m)
            for m in self.settings.MODULES["auth_post"]
        ]
        self.acct_post = [
            importlib.import_module(m)
            for m in self.settings.MODULES["acct_post"]
        ]

    def handleAuth(self, socket, data, address):
        """
        auth request handle

        :param socket:
        :param data:
        :param address:

        :return:
        """
        try:
            req = self.parseAuthPacket(data, address)
            prereply = self.processAuth(req)
            reply = self.authReply(req, prereply)
            self.pool.spawn(socket.sendto, reply.ReplyPacket(), address)
        except Exception as e:
            self.logger.error("Handle Radius Auth error {}".format(e.message),
                              exc_info=True)

    def handleAcct(self, socket, data, address):
        """
        acct request handle

        :param socket:
        :param data:
        :param address:

        :return:
        """
        try:
            req = self.parseAcctPacket(data, address)
            prereply = self.processAcct(req)
            reply = self.acctReply(req, prereply)
            self.pool.spawn(socket.sendto, reply.ReplyPacket(), address)
        except Exception as e:
            self.logger.error("Handle Radius Acct error {}".format(e.message),
                              exc_info=True)

    def getClients(self):
        """
        fetch nas clients

        Usage example::

            def getClients(self):
                nas = dict(
                    status=1,
                    nasid='toughac',
                    name='toughac',
                    vendor=0,
                    ipaddr='127.0.0.1',
                    secret='testing123',
                    coaport=3799
                )
                return { 'toughac' : nas, '127.0.0.1' : nas}

        :return: nas dict
        """
        raise NotImplementedError('Attempted to use a pure base class')

    @staticmethod
    def verifyAcctRequest(req):
        """
        verify radius accounting request

        :param req:
        """
        if req.code != packet.AccountingRequest:
            errstr = u'Invalid accounting request code=%s' % req.code
            raise packet.PacketError(errstr)

        if not req.VerifyAcctRequest():
            errstr = u'The accounting response check failed. Check that the shared key is consistent'
            raise packet.PacketError(errstr)

    @staticmethod
    def freeReply(req, **params):
        """
        gen free auth response

        :param req:
        :param params:

        :return:
        """
        reply = req.CreateReply()
        reply.vendor_id = req.vendor_id
        reply[
            'Reply-Message'] = u'User:%s (Free)Authenticate Success' % req.get_user_name(
            )
        reply.code = packet.AccessAccept
        reply_attrs = dict(attrs={})
        reply_attrs['input_rate'] = params.pop("free_auth_input_limit",
                                               1048576)
        reply_attrs['output_rate'] = params.pop("free_auth_output_limit",
                                                4194304)
        reply_attrs['rate_code'] = params.pop("free_auth_rate_code", "")
        reply_attrs['domain'] = params.pop("free_auth_domain", "")
        reply_attrs['attrs']['Session-Timeout'] = params.pop(
            "max_session_timeout", 86400)
        reply.resp_attrs = reply_attrs
        return reply

    @staticmethod
    def rejectReply(req, errmsg=''):
        """
        gen reject radius auth response

        :param req:
        :param errmsg:

        :return:
        """
        reply = req.CreateReply()
        reply.vendor_id = req.vendor_id
        reply['Reply-Message'] = errmsg
        reply.code = packet.AccessReject
        return reply

    def parseAuthPacket(self, datagram, (host, port)):
        """
        parse radius auth request

        :param datagram:

        :return:  pyrad.message
        """
        clients = self.getClients()
        vendors = self.settings.VENDORS
        if host in clients:
            client = clients[host]
            request = message.AuthMessage(packet=datagram,
                                          dict=self.dictionary,
                                          secret=str(client['secret']))
            request.vendor_id = vendors.get(client['vendor'])
        else:
            request = message.AuthMessage(packet=datagram,
                                          dict=self.dictionary,
                                          secret=six.b(''))
            nas_id = request.get_nas_id()
            if nas_id in clients:
                client = clients[nas_id]
                request.vendor_id = vendors.get(client['vendor'])
                request.secret = six.b(client['secret'])
            else:
                raise packet.PacketError(
                    "Unauthorized Radius Access Device [%s] (%s:%s)" %
                    (nas_id, host, port))
        if request.code != packet.AccessRequest:
            errstr = u'Invalid authenticator request code=%s' % request.code
            raise packet.PacketError(errstr)
        request.source = (host, port)
        for _module in self.auth_pre:
            request = _module.handle_radius(request)
        return request
Пример #18
0
def send_coadm(server,
               port=3799,
               secret=six.b("testing123"),
               debug=False,
               dictfile=None,
               **kwargs):
    """
    send coa disconnect request to nas

    :param server: nas server ipaddr
    :param port: coa port, default 3799

    :param secret: nas share secret
    :param debug: logging level

    :param dictfile: dictionary file path
    :param kwargs: request params

    :return: coa response
    """
    try:
        radius_dictionary = get_dictionary(dictfile=dictfile)
        timeout_sec = kwargs.pop('timeout', 5)
        result = kwargs.pop('result', True)
        vendor_id = kwargs.pop('vendor_id', 0)
        request = message.CoAMessage(code=packet.DisconnectRequest,
                                     dict=radius_dictionary,
                                     secret=secret,
                                     **kwargs)
        username = request["User-Name"][0]
        if vendor_id == ikuai.VENDOR_ID:
            pkg = ikuai.create_dm_pkg(secret, username)
            if debug:
                logger.debug(
                    "Send ikuai radius CoaDmRequest to (%s:%s) [username:%s]: %s"
                    % (server, port, username, repr(pkg)))
        else:
            pkg = request.RequestPacket()
            if debug:
                logger.debug(
                    "Send radius CoaDmRequest to (%s:%s) [username:%s]: %s" %
                    (server, port, username, request.format_str()))

        sock = socket.socket(type=socket.SOCK_DGRAM)
        sock.settimeout(timeout_sec)
        sock.connect((server, port))
        sock.send(pkg)
        if result:
            data, address = sock.recvfrom(8192)
            if vendor_id != ikuai.VENDOR_ID:
                reply = request.CreateReply(packet=data)
                if debug:
                    logger.debug(
                        "Recv radius coa dm response from (%s:%s): %s" %
                        (server, port, reply.format_str()))
                return reply
            else:
                if debug:
                    logger.debug(
                        "Recv radius ik coa dm response from (%s:%s): %s" %
                        (server, port, repr(data)))
                return data
    except Exception as e:
        logger.error("accounting error {}".format(e.message), exc_info=True)
Пример #19
0
        :param datagram:

        :return: pyrad.message
        """
        clients = self.getClients()
        vendors = self.settings.VENDORS
        if host in clients:
            client = clients[host]
            request = message.AcctMessage(packet=datagram,
                                          dict=self.dictionary,
                                          secret=str(client['secret']))
            request.vendor_id = vendors.get(client['vendor'])
        else:
            request = message.AcctMessage(packet=datagram,
                                          dict=self.dictionary,
                                          secret=six.b(''))
            nas_id = request.get_nas_id()
            if nas_id in clients:
                client = clients[nas_id]
                request.vendor_id = vendors.get(client['vendor'])
                request.secret = six.b(client['secret'])
            else:
                raise packet.PacketError(
                    "Unauthorized Radius Access Device [%s] (%s:%s)" %
                    (nas_id, host, port))
        self.verifyAcctRequest(request)
        request.source = (host, port)
        for _module in self.acct_pre:
            request = _module.handle_radius(request)
        return request