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()
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()
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
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())
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) )))
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
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
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()
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())
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))
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
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
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
def import_modules(sender, *args, **kwargs): global engine config = get_config() engine = create_engine(config)
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)}
def setup_engine(sender, *args, **kwargs): global engine config = get_config() engine = create_engine(config)
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_(
def add_globals(): return {'constants': constants, 'config': get_config(runtime_checks=True)}
def init_engine(): global engine config = get_config(runtime_checks=True) engine = create_engine(config)
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)