Beispiel #1
0
    def __init__(self, config_path=DEFAULT_CONFIG_PATH):
        if not os.path.isfile(config_path):
            raise DDTBError('No such file: %s' % config_path)

        try:
            config = configobj.ConfigObj(config_path)
        except configobj.ParseError, e:
            raise DDTBError(e)
Beispiel #2
0
    def changeUserPassword(self, apikey, id, newPlaintextPassword):
        if self._checkAPIKey(apikey):
            login = self._userLogin(base64.b64decode(id).decode('utf-8'))
            if not login:
                return DDTBError('Client with login %s not found' % login)

            iv = self.crypt.get_new_iv()
            if self.db_key is not None:
                newPassword = base64.b64encode(
                    self.crypt.encryptPassword(
                        iv, base64.b64decode(newPlaintextPassword),
                        self.db_key))
            else:
                newPassword = newPlaintextPassword

            try:
                self.database.update_password(login, base64.b64encode(iv),
                                              newPassword)
                self.database.store.autoreload()
                self.sessions.manager.change_user_cache(login)
                logs.ipc.info(
                    "Password for user with login %s successfully changed" %
                    login)
                return True
            except DDTBError, e:
                logs.ipc.error("Password for user with login %s NOT changed" %
                               login)
                return e
Beispiel #3
0
    def removeUser(self, apikey, id):
        if self._checkAPIKey(apikey):
            #try:
            #    killTunnel(self, apikey, login)
            #except:
            #    pass

            login = self._userLogin(base64.b64decode(id).decode('utf-8'))
            if not login:
                return DDTBError('Client with login %s not found' % login)
            try:
                self.database.unregister_client(login=login.encode('utf-8'))
                self.database.store.autoreload()
                if self.sessions.manager.auth.user_cache.has_key(login):
                    del self.sessions.manager.auth.user_cache[login]
                    logs.ipc.debug('User %s removed from user cache.' % login)
                else:
                    logs.ipc.error(
                        "User with login %s was NOT found in user cache, could not remove."
                        % (login))
                    return False

                logs.ipc.info("User with login %s successfully removed." %
                              login)
                return True
            except DDTBError, e:
                print 'Error removing user %s: %s' % (login, e)
class DDTBDatabase(object):
    """
    Database access class for database queries.
    """
    def __init__(self, config):
        """
        The connection parameter should be a valid storm ORM DB
        access string, for example:
            mysql://ddtb:ddtbpassword@localhost:3306/TB
        """
        if re.search("[^a-zA-Z0-9_\+=_\-]", config.database.password):
            error = 'Database user ' + config.database.user + ' password contains illegal character (for example, "/" is not allowed).'
            raise DDTBError(error)

        self.database = create_database(config.database.connection)
        self.__store = None

    def __getattr__(self, attr):
        if attr == 'store':
            if self.__store is None:
                try:
                    self.__store = Store(self.database)
                except OperationalError, e:
                    raise DDTBError('Error connecting to database: %s' % e[1])
                except:
                    raise DDTBError('Error opening database store')
 def register_client(self, login, name, iv, passwd, email, mobile,
                     ipaddress, max_prefix, min_prefix):
     """
     Register a new client entry to the database
     """
     try:
         self.store.find(Client, Client.login == unicode(login))[0]
         raise DDTBError('Customer already registered: %s' % unicode(login))
     except IndexError:
         pass
     client = Client()
     client.login = unicode(login)
     client.name = unicode(name)
     client.iv = unicode(iv)
     client.passwd = unicode(passwd)
     client.email = unicode(email)
     client.mobile = unicode(mobile)
     client.ipaddress = unicode(ipaddress)
     client.min_prefix = min_prefix
     client_max_prefix = max_prefix
     self.store.add(client)
     self.store.flush()
     self.store.commit()
     logs.auth.info('Registered client: %s (%s)' % (login, name))
     self.__store = None
     return client.id
Beispiel #6
0
 def init_system(self):
     for cmd in TTDB_INIT_COMMANDS:
         cmd = cmd % self.broker
         logs.ddtb.debug('Running: %s' % cmd)
         retval = call(cmd.split())
         if retval != 0:
             raise DDTBError('Error running command %s' % cmd)
Beispiel #7
0
 def __init__(self, config):
     DDTBAuthenticator.__init__(self, config)
     self.method = 'DIGEST-MD5'
     self.service = 'tsp'
     try:
         self.server = config.auth.server
     except KeyError:
         raise DDTBError('SASL server address not configured.')
 def __getattr__(self, attr):
     if attr == 'store':
         if self.__store is None:
             try:
                 self.__store = Store(self.database)
             except OperationalError, e:
                 raise DDTBError('Error connecting to database: %s' % e[1])
             except:
                 raise DDTBError('Error opening database store')
Beispiel #9
0
def DDTBLoadAuthenticator(config):
    method = config.auth.method
    path = 'ddtb.authmethods.%s' % method
    classname = '%sAuthentication' % method
    m = __import__(path, globals(), fromlist=[method])
    return getattr(m, classname)(config)
    try:
        pass
    except (ImportError, AttributeError):
        raise DDTBError('Error loading authenticator for %s' % method)
Beispiel #10
0
 def __init__(self, name, data):
     DDTBConfigSection.__init__(self, name, data)
     if self.engine == 'mysql':
         try:
             self.connection = 'mysql://%(user)s:%(password)s@%(host)s:%(port)s/%(database)s' % self
         except KeyError:
             raise DDTBError(
                 'Database configuration missing required values.')
     else:
         raise NotImplementedError('Only MySQL is supported for now.')
Beispiel #11
0
    def __init__(self,config):
        for k,v in config.items():
            setattr(self,k,v)

        if not os.path.isdir(self.logdir):
            raise DDTBError('No such directory: %s' % self.logdir)

        try:
            ddtblog = os.path.join(self.logdir,'ddtb.log')
            self['ddtb'] = DDTBLogFile(
                program='ddtb',
                path=ddtblog,
                logformat=LOGFORMAT,
                level=logging.DEBUG,
                max_bytes=self.max_bytes,
                rotations=self.rotations
            )
        except IOError,(ecode,emsg):
            raise DDTBError('Error opening %s: %s' % (ddtblog,emsg))
Beispiel #12
0
class DDTBConfig(dict):
    def __init__(self, config_path=DEFAULT_CONFIG_PATH):
        if not os.path.isfile(config_path):
            raise DDTBError('No such file: %s' % config_path)

        try:
            config = configobj.ConfigObj(config_path)
        except configobj.ParseError, e:
            raise DDTBError(e)
        except IOError, (ecode, emsg):
            raise DDTBError('Error opening %s: %s' % (config_path, emsg))
 def __init__(self, database, address, allocation_size):
     """
     Class to iterate possible address prefixes in given address pools, 
     looking for unallocated pool.
     """
     self.database = database
     try:
         self.address = address
         self.prefixes = SubnetPrefixIterator(address, allocation_size)
         self.allocation_size = allocation_size
     except ValueError, e:
         raise DDTBError('Error creating address pool: %s' % e)
    def __init__(self, config):
        """
        The connection parameter should be a valid storm ORM DB
        access string, for example:
            mysql://ddtb:ddtbpassword@localhost:3306/TB
        """
        if re.search("[^a-zA-Z0-9_\+=_\-]", config.database.password):
            error = 'Database user ' + config.database.user + ' password contains illegal character (for example, "/" is not allowed).'
            raise DDTBError(error)

        self.database = create_database(config.database.connection)
        self.__store = None
Beispiel #15
0
    def __init__(self, name, data):
        DDTBConfigSection.__init__(self, name, data)

        if not self.has_key('logdir'):
            self['logdir'] = DEFAULT_LOG_DIRECTORY
        if not self.has_key('rotations'):
            self['rotations'] = DEFAULT_LOG_ROTATIONS
        if not self.has_key('max_bytes'):
            self['max_bytes'] = DEFAULT_LOG_MAX_BYTES
        if not self.has_key('owner'):
            self['owner'] = DEFAULT_LOG_OWNER
        if not self.has_key('group'):
            self['group'] = DEFAULT_LOG_GROUP

        try:
            self['uid'] = pwd.getpwnam(str(self['owner']).strip()).pw_uid
        except KeyError:
            raise DDTBError('User for logs %s not found.' % self.owner)
        try:
            self['gid'] = grp.getgrnam(str(self['group']).strip()).gr_gid
        except KeyError:
            raise DDTBError('Group for logs %s not found.' % self.group)

        try:
            self['rotations'] = int(self['rotations'])
            if self.rotations < 0 or self.rotations > MAX_ROTATIONS:
                raise ValueError
        except ValueError:
            raise DDTBError('Invalid logging rotations value: %s' %
                            self['rotations'])
        try:
            self['max_bytes'] = int(self['max_bytes'])
            if self.max_bytes < 1024 or self.max_bytes > LOG_BYTES_LIMIT:
                raise ValueError
        except ValueError:
            raise DDTBError('Invalid logging max_bytes value: %s' %
                            self['max_bytes'])

        if not os.path.isdir(self['logdir']):
            raise DDTBError('No such directory: %s' % self.logdir)
Beispiel #16
0
    def __init__(self, tunnel_manager, flags):
        self.tunnel_manager = tunnel_manager
        if type(flags) != dict:
            raise DDTBError('TSPTunnelConfig requires a dict as parameter')

        for k in TSP_MANDATORY_FLAGS:
            if not flags.has_key(k):
                raise DDTBError('Missing mandatory flag: %s' % k)

        self.update(flags)
        self['server_port'] = tunnel_manager.server_port
        (self['prefix_network'],
         self['prefix_mask']) = self['prefix'].split('/')

        # Example interface name: c0a00101_1234
        self['interface'] = '%s_%04d' % (''.join([
            '%02x' % int(x) for x in self['client_ipv4'].split('.')
        ]), int(self['client_port']))

        # Ifindex is only initialized when the tunnel is configured or
        # deconfigure is attempted
        self['ifindex'] = None
 def unregister_tunnel(self, tunnel_id):
     """
     Remove registeration for given tunnel with given user ID
     """
     try:
         tunnel = self.store.find(Tunnel, Tunnel.id == tunnel_id)[0]
         client_login = tunnel.client.login
         self.store.remove(tunnel)
         self.store.commit()
         logs.auth.info("Tunnel for client %s closed" % client_login)
     except IndexError:
         raise DDTBError('No such tunnel ID: %s' % tunnel_id)
     self.__store = None
Beispiel #18
0
    def __init__(self, name, data):
        DDTBConfigSection.__init__(self, name, data)

        if not self.has_key('allocation_prefix'):
            raise DDTBError('Missing IPv6 client allocation prefix.')

        try:
            IPv6Address(self['allocation_prefix']).address
        except ValueError:
            raise DDTBError('Invalid IPv6 allocation prefix: %s' %
                            self['allocation_prefix'])

        if not self.has_key('customer_prefix_size'):
            self['customer_prefix_size'] = DEFAULT_PREFIX_SIZE
        try:
            customer_prefix_size = int(self['customer_prefix_size'])
            if customer_prefix_size <= 1 or customer_prefix_size >= 2**7:
                raise ValueError
            self['customer_prefix_size'] = customer_prefix_size
        except ValueError:
            raise DDTBError('Invalid customer prefix size %s' %
                            self['customer_prefix_size'])
 def create_database_tables(self):
     """
     Create empty database tables based on our database model. Note that
     an empty database with GRANT ALL ON <database>.* must be executed and
     user account created to DB before this can be done. We only create
     tables, not databases or accounts.
     """
     for cmd in DDTB_MYSQL_TABLES:
         try:
             self.store.execute(cmd)
         except ProgrammingError:
             raise DDTBError('Error creating database tables')
     self.store.commit()
     self.__store = None
Beispiel #20
0
    def configure(self):
        """
        Configure a TSP tunnel interface and associated iptables and routing
        policy rules for it.
        """

        logs.ddtb.info('Configuring tunnel interface %s' % self.interface)
        for cmd in TSP_TUNNEL_LINK_SETUP_COMMANDS:
            cmd = cmd % self
            #            logs.ddtb.debug('Running cmd: %s' % cmd)
            retval = call(cmd.split())
            if retval != 0:
                raise DDTBError('Error running command %s' % cmd)
        try:
            self['ifindex'] = '%s' % int(self.get_ifindex())
            self['utun_table'] = '%s' % (int(self.ifindex) + TSP_RTABLE_OFFSET)
        except ValueError:
            logs.ddtb.debug('Interface was not configured: %s' %
                            self.interface)
            raise

        for queue in TSP_MANGLE_QUEUES:
            params = dict(self)
            params['queue'] = queue
            cmd = TSP_MANGLE_COMMAND % params
            #            logs.ddtb.debug('Running cmd: %s' % cmd)
            retval = call(cmd.split())
            if retval != 0:
                raise DDTBError('Error running mangle command %s' % cmd)

        for cmd in TSP_TUNNEL_IPTABLES_ROUTING:
            cmd = cmd % self
            #            logs.ddtb.debug('Running cmd: %s' % cmd)
            retval = call(cmd.split())
            if retval != 0:
                raise DDTBError('Error running command: %s' % ' '.join(cmd))
Beispiel #21
0
    def __init__(self, name, data):
        DDTBConfigSection.__init__(self, name, data)

        try:
            self['active'] = bool(self['active'])
        except KeyError:
            raise DDTBError('RPC "active" flag required')

        if self['active'] and not (self.has_key('apikey')
                                   or len(self['apikey'] == 0)):
            raise DDTBError('RPC api key required')

        try:
            self['rpcip'] = IPv4Address(self['rpcip']).ipaddress
        except ValueError:
            raise DDTBError('Invalid broker %s: %s' % (k, self[k]))

        try:
            port = int(self['port'])
            if port <= 0 or port >= 2**16:
                raise ValueError
            self['port'] = port
        except ValueError:
            raise DDTBError('Invalid XML-RPC IPC port: %s' % self['port'])
    def update_password(self, login, iv, NewPasswd):
        try:
            self.store.find(
                Client,
                Client.login == unicode(login)).set(passwd=unicode(NewPasswd))
            self.store.find(Client,
                            Client.login == unicode(login)).set(iv=unicode(iv))
            self.store.commit()
            self.__store = None
            return True

        except IndexError:
            raise DDTBError(
                'Client with login %s not found, cannot update password' %
                login)
 def unregister_client(self, login):
     """
     Unregister a client entry from the database
     """
     self.store.flush()
     try:
         client = self.store.find(
             Client, Client.login == unicode(login.decode('utf8')))[0]
         logs.auth.info('Unregistering client: %s (%s)' %
                        (client.login, client.name))
         self.store.remove(client)
         self.store.commit()
     except IndexError:
         raise DDTBError('No such client: %s' % login)
     self.__store = None
Beispiel #24
0
    def userDetails(self, apikey, id):
        if self._checkAPIKey(apikey):
            login = self._userLogin(id)
            if not login:
                return DDTBError('Client with login %s not found' % login)

            client = self.database.client_details(login)
            # Easy client to dict conversion, casting doesn't work
            fieldList = ['login', 'name', 'email', 'mobile', 'ipaddress']
            clientList = [
                client.login, client.name, client.email, client.mobile,
                client.ipaddress
            ]
            return dict(zip(fieldList, clientList))
        else:
            return TBRPCInvalidAPIKEYError('userDetails')
Beispiel #25
0
 def get_ifindex(self):
     """
     Return ifindex of tunnel interface, raise ValueError if not configured.
     """
     cmd = ['ip', 'link', 'list', self.interface]
     p = Popen(cmd, stdout=PIPE, stderr=PIPE)
     stdout, stderr = p.communicate()
     if stdout.rstrip() == 'Device "%s" does not exist.' % self.interface:
         raise ValueError
     if p.returncode != 0:
         raise ValueError
     try:
         # Note - we return this as string, not int
         self.ifindex = stdout.split(':')[0]
         return self.ifindex
     except IndexError:
         raise DDTBError('Error splitting ifindex from %s' % stdout)
 def register_prefix(self, client_id, prefix):
     """
     Register a single prefix for given client_id
     """
     self.store.flush()
     entry = Prefix()
     try:
         client = self.store.find(Client, Client.id == client_id)[0]
     except IndexError:
         raise DDTBError('No such client: %s' % client_id)
     entry.client_id = client.id
     entry.prefix = unicode(prefix.network)
     entry.prefixlen = prefix.mask
     entry.type = unicode(prefix.prefix_type)
     self.store.add(entry)
     self.store.commit()
     self.__store = None
    def checkLogin(self, login, passwd):
        try:
            entry = self.store.find(Client,
                                    Client.login == unicode(login)).one()
            if not entry:
                logs.auth.info("Client with login %s not found." % login)
                return False
            elif not unicode(passwd) == entry.passwd:
                logs.auth.info(
                    "Client with login %s tried wrong credentials." % login)
                return False

            logs.auth.info("Client with login %s authenticated." % login)
            return True

        except IndexError:
            raise DDTBError('Client with login %s not found (IndexError).' %
                            login)
 def find_next(self, user_id=None):
     """
     Returns next prefix from this pool
     """
     # TODO - think when to actually update this from DB, not every time.
     # In general, this may need lots of refactoring!
     self.update_db_prefix_cache()
     while True:
         try:
             ca = CustomerAllocation(self, self.prefixes.next(), user_id)
             try:
                 existing = self[ca.network]
                 if existing.user_id == user_id:
                     # Return user's network
                     return ca
                 else:
                     # Allocated to someone else
                     continue
             except KeyError:
                 self.database.register_prefix(user_id, ca)
                 self[ca.network] = ca
                 return ca
         except StopIteration:
             raise DDTBError('No more Ipv6 prefixes in %s' % self.address)
Beispiel #29
0
class DDTBLogs(dict):
    """
    Initialize the logging facilities available for DDTB
    """
    def __init__(self,config):
        for k,v in config.items():
            setattr(self,k,v)

        if not os.path.isdir(self.logdir):
            raise DDTBError('No such directory: %s' % self.logdir)

        try:
            ddtblog = os.path.join(self.logdir,'ddtb.log')
            self['ddtb'] = DDTBLogFile(
                program='ddtb',
                path=ddtblog,
                logformat=LOGFORMAT,
                level=logging.DEBUG,
                max_bytes=self.max_bytes,
                rotations=self.rotations
            )
        except IOError,(ecode,emsg):
            raise DDTBError('Error opening %s: %s' % (ddtblog,emsg))

        try:
            sessionlog = os.path.join(self.logdir,'session.log')
            self['session'] = DDTBLogFile(
                program='session',
                path=sessionlog,
                logformat=LOGFORMAT,
                level=logging.DEBUG,
                max_bytes=self.max_bytes,
                rotations=self.rotations
            )
        except IOError,(ecode,emsg):
            raise DDTBError('Error opening %s: %s' % (sessionlog,emsg))
Beispiel #30
0
    def __init__(self, name, data):
        DDTBConfigSection.__init__(self, name, data)

        for opt in BROKER_REQUIRED_CONFIG_KEYS:
            if not self.has_key(opt):
                raise DDTBError('Missing broker configuration for %s' % opt)

        try:
            validate_hostname(self['hostname'])
        except ValueError:
            raise DDTBError('Invalid broker hostname: %s' % self['hostname'])
        for k in ['tunnelip', 'serverip']:
            try:
                self[k] = IPv4Address(self[k]).ipaddress
            except ValueError:
                raise DDTBError('Invalid broker %s: %s' % (k, self[k]))
        try:
            port = int(self['port'])
            if port <= 0 or port >= 2**16:
                raise ValueError
            self['port'] = port
        except ValueError:
            raise DDTBError('Invalid broker port: %s' % self['port'])

        if not self.has_key('cleanup_interval'):
            self['cleanup_interval'] = DEFAULT_CLEANUP_INTERVAL
        try:
            self['cleanup_interval'] = int(self['cleanup_interval'])
        except ValueError:
            raise DDTBError('Invalid broker cleanup_interval %s' %
                            self['cleanup_interval'])

        if not self.has_key('keepalive_interval'):
            self['keepalive_interval'] = DEFAULT_KEEPALIVE_INTERVAL
        try:
            self['keepalive_interval'] = int(self['keepalive_interval'])
        except ValueError:
            raise DDTBError('Invalid broker keepalive_interval %s' %
                            self['keepalive_interval'])