Пример #1
0
def run_event_loop():
    bus = SystemBus()
    logger.debug('Publishing interface %s on DBus', constants.DEPUTY_DBUS_NAME)
    config = get_config()
    bus.publish(constants.DEPUTY_DBUS_NAME, HadesDeputyService(bus, config))
    loop = GLib.MainLoop()
    loop.run()
Пример #2
0
def get_latest_auth_attempt(
    connection: Connection, mac: netaddr.EUI
) -> Optional[Tuple[netaddr.IPAddress, str, Tuple[str], Tuple[Tuple[str]],
                    datetime]]:
    """
    Get the latest auth attempt of a MAC address that occurred within twice the
    reauthentication interval.

    :param connection: A SQLAlchemy connection
    :param str mac: MAC address
    :return: A (NAS-IP-Address, NAS-Port-Id, Groups, Reply, Auth-Date) tuple
    or None if no attempt was found. Groups is an tuple of group names and Reply
    is a tuple of (Attribute, Value)-pairs that were sent in the Access-Accept
    response.
    """
    logger.debug('Getting latest auth attempt for MAC "%s"', mac)
    config = get_config(runtime_checks=True)
    interval = config.HADES_REAUTHENTICATION_INTERVAL
    return connection.execute(
        select([
            radpostauth.c.NASIPAddress, radpostauth.c.NASPortId,
            radpostauth.c.Groups, radpostauth.c.Reply, radpostauth.c.AuthDate
        ]).where(
            and_(
                radpostauth.c.UserName == mac,
                radpostauth.c.AuthDate >= (utcnow() - interval),
                radpostauth.c.PacketType == 'Access-Accept',
            )).order_by(radpostauth.c.AuthDate.desc()).limit(1)).first()
Пример #3
0
def run_event_loop():
    bus = SystemBus()
    logger.debug('Publishing interface %s on DBus', constants.DEPUTY_DBUS_NAME)
    config = get_config()
    bus.publish(constants.DEPUTY_DBUS_NAME, HadesDeputyService(bus, config))
    loop = GLib.MainLoop()
    loop.run()
Пример #4
0
def notify_root(state, priority) -> int:
    config = get_config(runtime_checks=True)
    app = create_app()
    app.config_from_object(config)
    queue_name = config.HADES_CELERY_NODE_QUEUE
    exchange_name = config.HADES_CELERY_RPC_EXCHANGE
    exchange_type = config.HADES_CELERY_RPC_EXCHANGE_TYPE
    routing_key = config.HADES_CELERY_SITE_ROUTING_KEY
    exchange = kombu.Exchange(exchange_name, exchange_type)
    with closing(app.connection(connect_timeout=1)) as connection:
        queue = app.amqp.queues[queue_name]
        bound_queue = queue.bind(connection.default_channel)
        if state == 'MASTER':
            logger.info(
                "Binding site node queue %s to RPC exchange %s "
                "with site routing key %s", queue_name, exchange_name,
                routing_key)
            bound_queue.bind_to(exchange=exchange, routing_key=routing_key)
        else:
            logger.info(
                "Unbinding site node queue %s from RPC exchange %s "
                "with site routing key %s", queue_name, exchange_name,
                routing_key)
            bound_queue.unbind_from(exchange=exchange, routing_key=routing_key)
    return 0
Пример #5
0
def update_alternative_dns_ipset(ips: Iterable[netaddr.IPAddress]) -> None:
    conf = get_config()
    ipset_name = conf['HADES_AUTH_DNS_ALTERNATIVE_IPSET']
    tmp_ipset_name = 'tmp_' + ipset_name
    logger.info("Updating alternative_dns ipset (%s)", ipset_name)
    commands = io.TextIOWrapper(io.BytesIO(), 'ascii')
    commands.writelines(generate_ipset_swap(ipset_name, tmp_ipset_name, ips))
    commands.flush()
    subprocess.run(
        [constants.IP, 'netns', 'exec', 'auth', constants.IPSET, 'restore'],
        input=commands.buffer.getvalue())
Пример #6
0
def delete_old():
    logger.info("Deleting old records")
    conf = get_config()
    connection = get_connection()
    with connection.begin() as trans:
        result = connection.execute(radacct.delete().where(and_(
            radacct.c.acctstoptime < utcnow() - conf["HADES_RETENTION_INTERVAL"]
        )))
        result = connection.execute(radpostauth.delete().where(and_(
            radpostauth.c.authdate < utcnow() - timedelta(days=1)
        )))
Пример #7
0
def update_alternative_dns_ipset(ips: Iterable[netaddr.IPAddress]) -> None:
    conf = get_config()
    ipset_name = conf['HADES_AUTH_DNS_ALTERNATIVE_IPSET']
    tmp_ipset_name = 'tmp_' + ipset_name
    logger.info("Updating alternative_dns ipset (%s)", ipset_name)
    commands = io.TextIOWrapper(io.BytesIO(), 'ascii')
    commands.writelines(generate_ipset_swap(ipset_name, tmp_ipset_name, ips))
    commands.flush()
    subprocess.run(
        [constants.IP, 'netns', 'exec', 'auth', constants.IPSET, 'restore'],
        input=commands.buffer.getvalue())
Пример #8
0
def main(args):
    config = CheckWrapper(get_config())
    try:
        with user(config['HADES_AGENT_USER']) as user_name:
            check_database(user_name, db.metadata.tables.values())
        with user(config['HADES_PORTAL_USER']) as user_name:
            check_database(user_name, (db.radacct, db.radpostauth,
                                       db.radusergroup))
        with user(config['HADES_RADIUS_USER']) as user_name:
            check_database(user_name, (db.nas, db.radacct, db.radgroupcheck,
                                       db.radgroupreply, db.radpostauth,
                                       db.radreply, db.radusergroup))
    except DBAPIError:
        return os.EX_TEMPFAIL
    return os.EX_OK
Пример #9
0
def main(args):
    if len(args) < 2:
        return os.EX_USAGE
    config = get_config()
    template_dir = pkg_resources.resource_filename('hades.config', 'templates')
    generator = ConfigGenerator(template_dir, config)
    name = args[1]
    source_path = os.path.join(template_dir, name)
    if os.path.isdir(source_path):
        return write_directory_config(name, generator, args)
    elif os.path.isfile(source_path):
        return write_single_file_config(name, generator, args)
    else:
        print("No such file or directory {} in {}".format(name, template_dir),
              file=sys.stderr)
        return os.EX_NOINPUT
Пример #10
0
def run_event_loop():
    """Run the DBus :class:`HadesDeputyService` on the GLib event loop."""
    with contextlib.ExitStack() as stack:
        bus: Bus = stack.enter_context(SystemBus())
        logger.debug("Publishing interface %s on DBus",
                     constants.DEPUTY_DBUS_NAME)
        config = get_config()
        stack.enter_context(
            bus.publish(constants.DEPUTY_DBUS_NAME,
                        HadesDeputyService(bus, config)))
        loop = GLib.MainLoop()
        stack.enter_context(
            install_handler(
                (signal.SIGHUP, signal.SIGINT, signal.SIGTERM),
                lambda _sig, _frame: loop.quit(),
            ))
        loop.run()
Пример #11
0
def main():
    if len(sys.argv) < 2:
        print("No config file specified")
        sys.exit(os.EX_USAGE)
    logger.info("dnsmasq monitor")
    conf_file = sys.argv[1]
    config = CheckWrapper(get_config())
    passwd = pwd.getpwnam(config['HADES_AUTH_DNSMASQ_USER'])
    group = grp.getgrnam(config['HADES_AUTH_DNSMASQ_GROUP'])
    sockfile = config['HADES_AUTH_DNSMASQ_SIGNAL_SOCKET']
    hosts_file = config['HADES_AUTH_DNSMASQ_HOSTS_FILE']
    if not os.path.exists(hosts_file):
        with open(hosts_file, mode='w'):
            pass
    args = ('dnsmasq', '--conf-file=' + conf_file)
    monitor = SignalProxyDaemon(sockfile, args, restart=True)
    os.chown(sockfile, passwd.pw_uid, group.gr_gid)
    drop_privileges(passwd, group)
    sys.exit(monitor.run())
Пример #12
0
def main():
    config = get_config()
    for name, value in config.items():
        escaped_name = escape(str(name))
        if isinstance(value, shell_types):
            print("export {}={}".format(escaped_name, escape(value)))
        elif isinstance(value, collections.Mapping):
            print("declare -A {}".format(name))
            for k, v in value.items():
                if isinstance(v, shell_types):
                    print("{}[{}]={}".format(escaped_name, escape(str(k)),
                                             escape(str(v))))
            print("export {}".format(escaped_name))
        elif isinstance(value, collections.Sequence):
            print("declare -a {}".format(name))
            for index, v in enumerate(value):
                if isinstance(v, shell_types):
                    print("{}[{}]={}".format(escaped_name, index,
                                             escape(str(v))))
            print("export {}".format(escaped_name))
Пример #13
0
def notify_radius(state, priority) -> int:
    config = get_config(runtime_checks=True)
    queue_name = config.HADES_CELERY_NODE_QUEUE
    exchange_name = config.HADES_CELERY_RPC_EXCHANGE
    exchange_type = config.HADES_CELERY_RPC_EXCHANGE_TYPE
    routing_key = config.HADES_CELERY_SITE_ROUTING_KEY
    exchange = kombu.Exchange(exchange_name, exchange_type)
    with closing(app.connection(connect_timeout=1)) as connection:
        queue = app.amqp.queues[queue_name]
        bound_queue = queue.bind(connection.default_channel)
        if state == 'MASTER':
            logger.info("Binding site node queue %s to RPC exchange %s "
                        "with site routing key %s",
                        queue_name, exchange_name, routing_key)
            bound_queue.bind_to(exchange=exchange, routing_key=routing_key)
        else:
            logger.info("Unbinding site node queue %s from RPC exchange %s "
                        "with site routing key %s",
                        queue_name, exchange_name, routing_key)
            bound_queue.unbind_from(exchange=exchange, routing_key=routing_key)
    return 0
Пример #14
0
Файл: db.py Проект: agdsn/hades
def get_latest_auth_attempt(connection: Connection,
                            mac: netaddr.EUI) -> Optional[Tuple[
        netaddr.IPAddress, str, str, Groups, Attributes, datetime]]:
    """
    Get the latest auth attempt of a MAC address that occurred within twice the
    reauthentication interval.

    :param connection: A SQLAlchemy connection
    :param str mac: MAC address
    :return: A (NAS-IP-Address, NAS-Port-Id, Packet-Type, Groups, Reply,
    Auth-Date) tuple or None if no attempt was found. Groups is an tuple of
    group names and Reply is a tuple of (Attribute, Value)-pairs that were sent
    in Access-Accept responses.
    """
    logger.debug('Getting latest auth attempt for MAC "%s"', mac)
    config = get_config(runtime_checks=True)
    interval = config.HADES_REAUTHENTICATION_INTERVAL
    attempts = get_auth_attempts_of_mac(connection, mac, (interval, None), 1)
    try:
        return next(attempts)
    except StopIteration:
        return None
Пример #15
0
def get_latest_auth_attempt(
    connection: Connection,
    mac: netaddr.EUI,
) -> Optional[Tuple[netaddr.IPAddress, str, str, Groups, Attributes,
                    datetime]]:
    """
    Get the latest auth attempt of a MAC address that occurred within twice the
    reauthentication interval.

    :param connection: A SQLAlchemy connection
    :param str mac: MAC address
    :return: A (NAS-IP-Address, NAS-Port-Id, Packet-Type, Groups, Reply,
        Auth-Date) tuple or None if no attempt was found. Groups is an tuple of
        group names and Reply is a tuple of (Attribute, Value)-pairs that were
        sent in Access-Accept responses.
    """
    logger.debug('Getting latest auth attempt for MAC "%s"', mac)
    config = get_config(runtime_checks=True)
    interval = config.HADES_REAUTHENTICATION_INTERVAL
    attempts = get_auth_attempts_of_mac(connection, mac, (interval, None), 1)
    try:
        return next(attempts)
    except StopIteration:
        return None
Пример #16
0
def import_modules(sender, *args, **kwargs):
    global engine
    config = get_config()
    engine = create_engine(config)
Пример #17
0
def add_globals():
    """Add the configure constants and the config object as global variable to
    the web portal's Jinja2 templates"""
    return {'constants': constants, 'config': get_config(runtime_checks=True)}
Пример #18
0
def setup_engine(sender, *args, **kwargs):
    global engine
    config = get_config()
    engine = create_engine(config)
Пример #19
0
from celery import Celery
from datetime import timedelta
import logging
from sqlalchemy import select, and_

from hades.common.db import (get_connection, radacct, radpostauth, utcnow)
from hades.config.loader import get_config

logger = logging.getLogger(__name__)
app = Celery(__name__)
app.config_from_object(get_config())


@app.task(rate_limit='1/m')
def refresh():
    logger.info("Refreshing materialized views")
    connection = get_connection()
    connection.execute("REFRESH MATERIALIZED VIEW radcheck")
    connection.execute("REFRESH MATERIALIZED VIEW radgroupcheck")
    connection.execute("REFRESH MATERIALIZED VIEW radgroupreply")
    connection.execute("REFRESH MATERIALIZED VIEW radusergroup")


@app.task(rate_limit='1/m')
def delete_old():
    logger.info("Deleting old records")
    connection = get_connection()
    result = connection.execute(radacct.delete().where(and_(
        radacct.c.acctstoptime < utcnow() - app.conf["HADES_RETENTION_INTERVAL"]
    )))
    result = connection.execute(radpostauth.delete().where(and_(
Пример #20
0
def add_globals():
    return {'constants': constants, 'config': get_config(runtime_checks=True)}
Пример #21
0
def init_engine():
    global engine
    config = get_config(runtime_checks=True)
    engine = create_engine(config)
Пример #22
0
import logging
import os
import signal

import netaddr

from hades.common.db import get_all_dhcp_hosts
from hades.config.loader import CheckWrapper, get_config

logger = logging.getLogger(__name__)
config = CheckWrapper(get_config())


def reload_auth_dnsmasq():
    pid_file = config['HADES_AUTH_DNSMASQ_PID_FILE']
    try:
        with open(pid_file) as f:
            pid = int(f.readline())
            if pid < 1:
                raise ValueError("PID must be > 0: %d", pid)
    except OSError as e:
        logger.error("Could not read PID file %s: %s", pid_file, e.strerror)
        return
    except (ValueError, OverflowError) as e:
        logger.error("Could not convert into PID: %s", str(e))
        return
    try:
        os.kill(pid, signal.SIGHUP)
    except OSError as e:
        logger.error("Can't send SIGHUP to pid %d: %s", pid, e.strerror)
Пример #23
0
def import_modules(sender, *args, **kwargs):
    global engine
    config = get_config()
    engine = create_engine(config)