def server_host_put(server_id, host_id): if settings.app.demo_mode: return utils.demo_blocked() svr = server.get_by_id(server_id) if not svr: return flask.abort(404) hst = host.get_by_id(host_id, fields=('_id', 'name', 'public_address', 'auto_public_address', 'auto_public_host', 'public_address6', 'auto_public_address6', 'auto_public_host6')) if not svr: return flask.abort(404) try: svr.add_host(hst.id) except ServerLinkCommonHostError: return utils.jsonify( { 'error': SERVER_LINK_COMMON_HOST, 'error_msg': SERVER_LINK_COMMON_HOST_MSG, }, 400) err, err_msg = svr.validate_conf(allow_online=True) if err: return utils.jsonify({ 'error': err, 'error_msg': err_msg, }, 400) svr.commit('hosts') event.Event(type=SERVER_HOSTS_UPDATED, resource_id=svr.id) return utils.jsonify({ 'id': hst.id, 'server': svr.id, 'status': OFFLINE, 'name': hst.name, 'address': hst.public_addr, })
def link_post(): if settings.local.sub_plan != 'enterprise_plus': return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() name = utils.filter_str(flask.request.json.get('name')) or 'undefined' lnk = link.Link( name=name, status=ONLINE, ) lnk.generate_key() lnk.commit() event.Event(type=LINKS_UPDATED) return utils.jsonify(lnk.dict())
def link_location_host_delete(link_id, location_id, host_id): if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) hst = loc.get_host(host_id) if not hst: return flask.abort(404) hst.remove() event.Event(type=LINKS_UPDATED) return utils.jsonify({})
def link_location_delete(link_id, location_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk or lnk.type == DIRECT: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) loc.remove() event.Event(type=LINKS_UPDATED) return utils.jsonify({})
def init(): settings.local.host = Host() try: settings.local.host.load() except NotFound: pass settings.local.host.status = ONLINE settings.local.host.users_online = 0 settings.local.host.start_timestamp = utils.now() settings.local.host.ping_timestamp = utils.now() if settings.local.public_ip: settings.local.host.auto_public_address = settings.local.public_ip try: settings.local.host.hostname = socket.gethostname() except: logger.exception('Failed to get hostname', 'host') settings.local.host.hostname = None if settings.conf.local_address_interface == 'auto': try: settings.local.host.local_address = socket.gethostbyname( socket.gethostname()) except: logger.exception('Failed to get local_address auto', 'host') settings.local.host.local_address = None else: try: settings.local.host.local_address = utils.get_interface_address( str(settings.conf.local_address_interface)) except: logger.exception('Failed to get local_address', 'host', interface=settings.conf.local_address_interface) settings.local.host.local_address = None settings.local.host.commit() event.Event(type=HOSTS_UPDATED)
def link_location_route_delete(link_id, location_id, network): if settings.local.sub_plan != 'enterprise_plus': return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) loc.remove_route(network) loc.commit('routes') event.Event(type=LINKS_UPDATED) return utils.jsonify({})
def link_put(link_id): if settings.local.sub_plan != 'enterprise_plus': return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) lnk.name = utils.filter_str(flask.request.json.get('name')) or 'undefined' status = flask.request.json.get('status') if status in (ONLINE, OFFLINE): lnk.status = status lnk.commit(('name', 'status')) event.Event(type=LINKS_UPDATED) return utils.jsonify(lnk.dict())
def link_location_put(link_id, location_id): if settings.local.sub_plan != 'enterprise_plus': return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) loc.name = utils.filter_str(flask.request.json.get('name')) or 'undefined' loc.commit('name') event.Event(type=LINKS_UPDATED) return utils.jsonify(loc.dict())
def link_put(link_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) lnk.name = utils.filter_str(flask.request.json.get('name')) or 'undefined' status = flask.request.json.get('status') if status in (ONLINE, OFFLINE): lnk.status = status if flask.request.json.get('key'): lnk.generate_key() lnk.ipv6 = True if flask.request.json.get('ipv6') else False lnk.host_check = True if flask.request.json.get('host_check') else False lnk.action = RESTART if flask.request.json.get( 'action') == RESTART else HOLD lnk.preferred_ike = utils.filter_str( flask.request.json.get('preferred_ike')) or None lnk.preferred_esp = utils.filter_str( flask.request.json.get('preferred_esp')) or None lnk.commit(('name', 'status', 'key', 'ipv6', 'host_check', 'action', 'preferred_ike', 'preferred_esp')) event.Event(type=LINKS_UPDATED) return utils.jsonify(lnk.dict())
def server_host_put(server_id, host_id): svr = server.get_by_id(server_id, fields=('_id', 'hosts', 'links')) hst = host.get_by_id(host_id, fields=('_id', 'name', 'public_address', 'auto_public_address')) try: svr.add_host(hst.id) except ServerLinkCommonHostError: return utils.jsonify({ 'error': SERVER_LINK_COMMON_HOST, 'error_msg': SERVER_LINK_COMMON_HOST_MSG, }, 400) svr.commit('hosts') event.Event(type=SERVER_HOSTS_UPDATED, resource_id=svr.id) return utils.jsonify({ 'id': hst.id, 'server': svr.id, 'status': OFFLINE, 'name': hst.name, 'address': hst.public_addr, })
def link_location_host_put(link_id, location_id, host_id): if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) hst = loc.get_host(host_id) if not hst: return flask.abort(404) hst.name = utils.filter_str(flask.request.json.get('name')) or 'undefined' hst.commit('name') event.Event(type=LINKS_UPDATED) return utils.jsonify(hst.dict())
def admin_delete(admin_id): if settings.app.demo_mode: return utils.demo_blocked() if not flask.g.administrator.super_user: return utils.jsonify( { 'error': REQUIRES_SUPER_USER, 'error_msg': REQUIRES_SUPER_USER_MSG, }, 400) admin = auth.get_by_id(admin_id) if admin.super_user and auth.super_user_count() < 2: return utils.jsonify({ 'error': NO_ADMINS, 'error_msg': NO_ADMINS_MSG, }, 400) admin.remove() event.Event(type=ADMINS_UPDATED) return utils.jsonify({})
def link_location_host_post(link_id, location_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) name = utils.filter_str(flask.request.json.get('name')) or 'undefined' timeout = int(flask.request.json.get('timeout') or 0) or None priority = abs(int(flask.request.json.get('priority') or 1)) or 1 hst = link.Host( link=lnk, location=loc, link_id=lnk.id, location_id=loc.id, name=name, timeout=timeout, priority=priority, ) hst.generate_secret() hst.commit() event.Event(type=LINKS_UPDATED) return utils.jsonify(hst.dict())
def link_location_peer_delete(link_id, location_id, peer_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk or lnk.type == DIRECT: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) loc.add_exclude(peer_id) lnk.commit('excludes') loc.commit('transit_excludes') event.Event(type=LINKS_UPDATED) return utils.jsonify({})
def link_location_peer_post(link_id, location_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk or lnk.type == DIRECT: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) peer_id = utils.ObjectId(flask.request.json.get('peer_id')) loc.remove_exclude(peer_id) lnk.commit('excludes') event.Event(type=LINKS_UPDATED) return utils.jsonify({})
def link_location_transit_post(link_id, location_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk or lnk.type == DIRECT: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) transit_id = database.ParseObjectId(flask.request.json.get('transit_id')) loc.add_transit(transit_id) loc.commit('transits') event.Event(type=LINKS_UPDATED) return utils.jsonify({})
def link_location_host_put(link_id, location_id, host_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk: return flask.abort(404) loc = lnk.get_location(location_id) if not loc: return flask.abort(404) hst = loc.get_host(host_id) if not hst: return flask.abort(404) hst.name = utils.filter_str(flask.request.json.get('name')) or 'undefined' hst.timeout = abs(int(flask.request.json.get('timeout') or 0)) or None hst.priority = abs(int(flask.request.json.get('priority') or 1)) or 1 hst.backoff = abs(int(flask.request.json.get('backoff') or 0)) or None hst.static = bool(flask.request.json.get('static')) hst.public_address = utils.filter_str( flask.request.json.get('public_address')) hst.local_address = utils.filter_str( flask.request.json.get('local_address')) hst.commit(('name', 'timeout', 'priority', 'backoff', 'static', 'public_address', 'local_address')) event.Event(type=LINKS_UPDATED) return utils.jsonify(hst.dict())
def link_location_post(link_id): if not settings.local.sub_plan or \ 'enterprise' not in settings.local.sub_plan: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() lnk = link.get_by_id(link_id) if not lnk or lnk.type == DIRECT: return flask.abort(404) name = utils.filter_str(flask.request.json.get('name')) or 'undefined' loc = link.Location( link=lnk, name=name, link_id=lnk.id, ) loc.commit() event.Event(type=LINKS_UPDATED) return utils.jsonify(loc.dict())
def send_link_events(self): event.Event(type=SERVER_LINKS_UPDATED, resource_id=self.id) for link in self.links: event.Event(type=SERVER_LINKS_UPDATED, resource_id=link['server_id'])
def _auth_plugin(username, password): if settings.local.sub_plan != 'enterprise': return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) valid, org_id, groups = sso.plugin_login_authenticate( user_name=username, password=password, remote_ip=utils.get_remote_addr(), ) if not valid: return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) if not org_id: logger.error( 'Login plugin did not return valid organization name', 'auth', org_name=org_id, user_name=username, ) return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) org = organization.get_by_id(org_id) if not org: return flask.abort(405) usr = org.find_user(name=username) if not usr: usr = org.new_user(name=username, type=CERT_CLIENT, auth_type=PLUGIN_AUTH, groups=list(groups) if groups else None) usr.audit_event( 'user_created', 'User created with plugin authentication', remote_addr=utils.get_remote_addr(), ) event.Event(type=ORGS_UPDATED) event.Event(type=USERS_UPDATED, resource_id=org.id) event.Event(type=SERVERS_UPDATED) else: if usr.disabled: return utils.jsonify({ 'error': AUTH_DISABLED, 'error_msg': AUTH_DISABLED_MSG, }, 403) if groups and groups - set(usr.groups or []): usr.groups = list(set(usr.groups or []) | groups) usr.commit('groups') if usr.auth_type != PLUGIN_AUTH: usr.auth_type = PLUGIN_AUTH usr.set_pin(None) usr.commit(('auth_type', 'pin')) key_link = org.create_user_key_link(usr.id, one_time=True) usr.audit_event('user_profile', 'User profile viewed from plugin authentication', remote_addr=utils.get_remote_addr(), ) return utils.jsonify({ 'redirect': utils.get_url_root() + key_link['view_url'], }, 202)
def _auth_radius(username, password): sso_mode = settings.app.sso valid, org_names, groups = sso.verify_radius(username, password) if not valid: return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) org_id = settings.app.sso_org if org_names: for org_name in org_names: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id break valid, org_id_new, groups2 = sso.plugin_sso_authenticate( sso_type='radius', user_name=username, user_email=None, remote_ip=utils.get_remote_addr(), ) if valid: org_id = org_id_new or org_id else: logger.error('Radius plugin authentication not valid', 'sso', username=username, ) return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) groups = ((groups or set()) | (groups2 or set())) or None if DUO_AUTH in sso_mode: try: duo_auth = sso.Duo( username=username, factor=settings.app.sso_duo_mode, remote_ip=utils.get_remote_addr(), auth_type='Key', ) valid = duo_auth.authenticate() except InvalidUser: logger.error('Duo authentication username not valid', 'sso', username=username, ) return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) if valid: valid, org_id_new, groups2 = sso.plugin_sso_authenticate( sso_type='duo', user_name=username, user_email=None, remote_ip=utils.get_remote_addr(), ) if valid: org_id = org_id_new or org_id else: logger.error('Duo plugin authentication not valid', 'sso', username=username, ) return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) groups = ((groups or set()) | (groups2 or set())) or None else: logger.error('Duo authentication not valid', 'sso', username=username, ) return utils.jsonify({ 'error': AUTH_INVALID, 'error_msg': AUTH_INVALID_MSG, }, 401) groups = ((groups or set()) | (groups2 or set())) or None org = organization.get_by_id(org_id) if not org: return flask.abort(405) usr = org.find_user(name=username) if not usr: usr = org.new_user(name=username, type=CERT_CLIENT, auth_type=sso_mode, groups=list(groups) if groups else None) usr.audit_event( 'user_created', 'User created with single sign-on', remote_addr=utils.get_remote_addr(), ) event.Event(type=ORGS_UPDATED) event.Event(type=USERS_UPDATED, resource_id=org.id) event.Event(type=SERVERS_UPDATED) else: if usr.disabled: return utils.jsonify({ 'error': AUTH_DISABLED, 'error_msg': AUTH_DISABLED_MSG, }, 403) if groups and groups - set(usr.groups or []): usr.groups = list(set(usr.groups or []) | groups) usr.commit('groups') if usr.auth_type != sso_mode: usr.auth_type = sso_mode usr.set_pin(None) usr.commit(('auth_type', 'pin')) key_link = org.create_user_key_link(usr.id, one_time=True) usr.audit_event('user_profile', 'User profile viewed from single sign-on', remote_addr=utils.get_remote_addr(), ) return utils.jsonify({ 'redirect': utils.get_url_root() + key_link['view_url'], }, 202)
def _run_thread(self, send_events): from pritunl.server.utils import get_by_id logger.debug( 'Starting ovpn process', 'server', server_id=self.server.id, ) self.resources_acquire() try: cursor_id = self.get_cursor_id() os.makedirs(self._temp_path) self.generate_ovpn_conf() self.enable_ip_forwarding() self.set_iptables_rules() self.process = self.openvpn_start() if not self.process: return self.start_threads(cursor_id) self.instance_com = ServerInstanceCom(self.server, self) self.instance_com.start() self.publish('started') if send_events: event.Event(type=SERVERS_UPDATED) event.Event(type=SERVER_HOSTS_UPDATED, resource_id=self.server.id) for org_id in self.server.organizations: event.Event(type=USERS_UPDATED, resource_id=org_id) for link_doc in self.server.links: if self.server.id > link_doc['server_id']: instance_link = ServerInstanceLink( server=self.server, linked_server=get_by_id(link_doc['server_id']), ) self.server_links.append(instance_link) instance_link.start() self.openvpn_watch() self.interrupt = True self.clear_iptables_rules() self.resources_release() if not self.clean_exit: event.Event(type=SERVERS_UPDATED) self.server.send_link_events() logger.LogEntry(message='Server stopped unexpectedly "%s".' % (self.server.name)) except: self.interrupt = True if self.resource_lock: self.clear_iptables_rules() self.resources_release() logger.exception( 'Server error occurred while running', 'server', server_id=self.server.id, ) finally: self.stop_threads() self.collection.update( { '_id': self.server.id, 'instances.instance_id': self.id, }, { '$pull': { 'instances': { 'instance_id': self.id, }, }, '$inc': { 'instances_count': -1, }, }) utils.rmtree(self._temp_path)
def send_event(self): for org_id in self.server.organizations: event.Event(type=USERS_UPDATED, resource_id=org_id) event.Event(type=HOSTS_UPDATED, resource_id=settings.local.host_id) event.Event(type=SERVERS_UPDATED)
def repeat_task(self): event.Event(type=ORGS_UPDATED)
def server_put_post(server_id=None): if settings.app.demo_mode: return utils.demo_blocked() used_resources = server.get_used_resources(server_id) network_used = used_resources['networks'] port_used = used_resources['ports'] name = None name_def = False if 'name' in flask.request.json: name_def = True name = utils.filter_str(flask.request.json['name']) network = None network_def = False if 'network' in flask.request.json: network_def = True network = flask.request.json['network'] try: if not _check_network_private(network): return _network_invalid() except (ipaddress.AddressValueError, ValueError): return _network_invalid() network_mode = None network_mode_def = False if 'network_mode' in flask.request.json: network_mode_def = True network_mode = flask.request.json['network_mode'] network_start = None network_start_def = False if 'network_start' in flask.request.json: network_start_def = True network_start = flask.request.json['network_start'] network_end = None network_end_def = False if 'network_end' in flask.request.json: network_end_def = True network_end = flask.request.json['network_end'] restrict_routes = None restrict_routes_def = False if 'restrict_routes' in flask.request.json: restrict_routes_def = True restrict_routes = True if flask.request.json['restrict_routes'] \ else False ipv6 = None ipv6_def = False if 'ipv6' in flask.request.json: ipv6_def = True ipv6 = True if flask.request.json['ipv6'] else False ipv6_firewall = None ipv6_firewall_def = False if 'ipv6_firewall' in flask.request.json: ipv6_firewall_def = True ipv6_firewall = True if flask.request.json['ipv6_firewall'] else False bind_address = None bind_address_def = False if 'bind_address' in flask.request.json: bind_address_def = True bind_address = utils.filter_str(flask.request.json['bind_address']) protocol = 'udp' protocol_def = False if 'protocol' in flask.request.json: protocol_def = True protocol = flask.request.json['protocol'].lower() if protocol not in ('udp', 'tcp'): return utils.jsonify({ 'error': PROTOCOL_INVALID, 'error_msg': PROTOCOL_INVALID_MSG, }, 400) port = None port_def = False if 'port' in flask.request.json: port_def = True port = flask.request.json['port'] try: port = int(port) except ValueError: return _port_invalid() if port < 1 or port > 65535: return _port_invalid() dh_param_bits = None dh_param_bits_def = False if flask.request.json.get('dh_param_bits'): dh_param_bits_def = True dh_param_bits = flask.request.json['dh_param_bits'] try: dh_param_bits = int(dh_param_bits) except ValueError: return _dh_param_bits_invalid() if dh_param_bits not in VALID_DH_PARAM_BITS: return _dh_param_bits_invalid() multi_device = False multi_device_def = False if 'multi_device' in flask.request.json: multi_device_def = True multi_device = True if flask.request.json['multi_device'] else False dns_servers = None dns_servers_def = False if 'dns_servers' in flask.request.json: dns_servers_def = True dns_servers = flask.request.json['dns_servers'] or [] for dns_server in dns_servers: try: ipaddress.IPAddress(dns_server) except (ipaddress.AddressValueError, ValueError): return _dns_server_invalid() search_domain = None search_domain_def = False if 'search_domain' in flask.request.json: search_domain_def = True search_domain = utils.filter_str(flask.request.json['search_domain']) inter_client = True inter_client_def = False if 'inter_client' in flask.request.json: inter_client_def = True inter_client = True if flask.request.json['inter_client'] else False ping_interval = None ping_interval_def = False if 'ping_interval' in flask.request.json: ping_interval_def = True ping_interval = flask.request.json['ping_interval'] if ping_interval: ping_interval = int(ping_interval) if not ping_interval: ping_interval = 10 ping_timeout = None ping_timeout_def = False if 'ping_timeout' in flask.request.json: ping_timeout_def = True ping_timeout = flask.request.json['ping_timeout'] if ping_timeout: ping_timeout = int(ping_timeout) if not ping_timeout: ping_timeout = 60 link_ping_interval = None link_ping_interval_def = False if 'link_ping_interval' in flask.request.json: link_ping_interval_def = True link_ping_interval = flask.request.json['link_ping_interval'] if link_ping_interval: link_ping_interval = int(link_ping_interval) if not link_ping_interval: link_ping_interval = 1 link_ping_timeout = None link_ping_timeout_def = False if 'link_ping_timeout' in flask.request.json: link_ping_timeout_def = True link_ping_timeout = flask.request.json['link_ping_timeout'] if link_ping_timeout: link_ping_timeout = int(link_ping_timeout) if not link_ping_timeout: link_ping_timeout = 5 onc_hostname = None onc_hostname_def = False if 'onc_hostname' in flask.request.json: onc_hostname_def = True onc_hostname = utils.filter_str(flask.request.json['onc_hostname']) max_clients = None max_clients_def = False if 'max_clients' in flask.request.json: max_clients_def = True max_clients = flask.request.json['max_clients'] if max_clients: max_clients = int(max_clients) if not max_clients: max_clients = 2000 replica_count = None replica_count_def = False if 'replica_count' in flask.request.json: replica_count_def = True replica_count = flask.request.json['replica_count'] if replica_count: replica_count = int(replica_count) if not replica_count: replica_count = 1 dns_mapping = False dns_mapping_def = False if 'dns_mapping' in flask.request.json: dns_mapping_def = True dns_mapping = True if flask.request.json['dns_mapping'] else False debug = False debug_def = False if 'debug' in flask.request.json: debug_def = True debug = True if flask.request.json['debug'] else False otp_auth = False otp_auth_def = False if 'otp_auth' in flask.request.json: otp_auth_def = True otp_auth = True if flask.request.json['otp_auth'] else False lzo_compression = False lzo_compression_def = False if 'lzo_compression' in flask.request.json: lzo_compression_def = True lzo_compression = True if flask.request.json[ 'lzo_compression'] else False cipher = None cipher_def = False if 'cipher' in flask.request.json: cipher_def = True cipher = flask.request.json['cipher'] if cipher not in CIPHERS: return utils.jsonify({ 'error': CIPHER_INVALID, 'error_msg': CIPHER_INVALID_MSG, }, 400) hash = None hash_def = False if 'hash' in flask.request.json: hash_def = True hash = flask.request.json['hash'] if hash not in HASHES: return utils.jsonify({ 'error': HASH_INVALID, 'error_msg': HASH_INVALID_MSG, }, 400) jumbo_frames = False jumbo_frames_def = False if 'jumbo_frames' in flask.request.json: jumbo_frames_def = True jumbo_frames = True if flask.request.json[ 'jumbo_frames'] else False if not server_id: if not name_def: return utils.jsonify({ 'error': MISSING_PARAMS, 'error_msg': MISSING_PARAMS_MSG, }, 400) if network_def and network_mode == BRIDGE and \ (not network_start or not network_end): return utils.jsonify({ 'error': MISSING_PARAMS, 'error_msg': MISSING_PARAMS_MSG, }, 400) if not network_def: network_def = True rand_range = range(215, 250) rand_range_low = range(15, 215) random.shuffle(rand_range) random.shuffle(rand_range_low) rand_range += rand_range_low for i in rand_range: rand_network = '192.168.%s.0/24' % i if not _check_network_overlap(rand_network, network_used): network = rand_network break if not network: return utils.jsonify({ 'error': NETWORK_IN_USE, 'error_msg': NETWORK_IN_USE_MSG, }, 400) if not port_def: port_def = True rand_ports = range(10000, 19999) random.shuffle(rand_ports) for rand_port in rand_ports: if '%s%s' % (rand_port, protocol) not in port_used: port = rand_port break if not port: return utils.jsonify({ 'error': PORT_PROTOCOL_IN_USE, 'error_msg': PORT_PROTOCOL_IN_USE_MSG, }, 400) if not dh_param_bits_def: dh_param_bits_def = True dh_param_bits = settings.vpn.default_dh_param_bits if network_def: if _check_network_overlap(network, network_used): return utils.jsonify({ 'error': NETWORK_IN_USE, 'error_msg': NETWORK_IN_USE_MSG, }, 400) if port_def: if '%s%s' % (port, protocol) in port_used: return utils.jsonify({ 'error': PORT_PROTOCOL_IN_USE, 'error_msg': PORT_PROTOCOL_IN_USE_MSG, }, 400) if not server_id: if network_mode == BRIDGE: if not _check_network_range(network, network_start, network_end): return utils.jsonify({ 'error': BRIDGE_NETWORK_INVALID, 'error_msg': BRIDGE_NETWORK_INVALID_MSG, }, 400) if ipv6: return utils.jsonify({ 'error': IPV6_BRIDGED_INVALID, 'error_msg': IPV6_BRIDGED_INVALID_MSG, }, 400) svr = server.new_server( name=name, network=network, network_mode=network_mode, network_start=network_start, network_end=network_end, restrict_routes=restrict_routes, ipv6=ipv6, ipv6_firewall=ipv6_firewall, bind_address=bind_address, port=port, protocol=protocol, dh_param_bits=dh_param_bits, multi_device=multi_device, dns_servers=dns_servers, search_domain=search_domain, otp_auth=otp_auth, cipher=cipher, hash=hash, jumbo_frames=jumbo_frames, lzo_compression=lzo_compression, inter_client=inter_client, ping_interval=ping_interval, ping_timeout=ping_timeout, link_ping_interval=link_ping_interval, link_ping_timeout=link_ping_timeout, onc_hostname=onc_hostname, max_clients=max_clients, replica_count=replica_count, dns_mapping=dns_mapping, debug=debug, ) svr.add_host(settings.local.host_id) svr.commit() else: svr = server.get_by_id(server_id) if svr.status == ONLINE: return utils.jsonify({ 'error': SERVER_NOT_OFFLINE, 'error_msg': SERVER_NOT_OFFLINE_SETTINGS_MSG, }, 400) for link_svr in svr.iter_links(fields=('status',)): if link_svr.status == ONLINE: return utils.jsonify({ 'error': SERVER_LINKS_NOT_OFFLINE, 'error_msg': SERVER_LINKS_NOT_OFFLINE_SETTINGS_MSG, }, 400) if name_def: svr.name = name if network_def: svr.network = network if network_start_def: svr.network_start = network_start if network_end_def: svr.network_end = network_end if restrict_routes_def: svr.restrict_routes = restrict_routes if ipv6_def: svr.ipv6 = ipv6 if ipv6_firewall_def: svr.ipv6_firewall = ipv6_firewall if network_mode_def: if network_mode == BRIDGE and ( not network_start or not network_end): return utils.jsonify({ 'error': MISSING_PARAMS, 'error_msg': MISSING_PARAMS_MSG, }, 400) svr.network_mode = network_mode if bind_address_def: svr.bind_address = bind_address if port_def: svr.port = port if protocol_def: svr.protocol = protocol if dh_param_bits_def and svr.dh_param_bits != dh_param_bits: svr.dh_param_bits = dh_param_bits svr.generate_dh_param() if multi_device_def: svr.multi_device = multi_device if dns_servers_def: svr.dns_servers = dns_servers if search_domain_def: svr.search_domain = search_domain if otp_auth_def: svr.otp_auth = otp_auth if cipher_def: svr.cipher = cipher if hash_def: svr.hash = hash if jumbo_frames_def: svr.jumbo_frames = jumbo_frames if lzo_compression_def: svr.lzo_compression = lzo_compression if inter_client_def: svr.inter_client = inter_client if ping_interval_def: svr.ping_interval = ping_interval if ping_timeout_def: svr.ping_timeout = ping_timeout if link_ping_interval_def: svr.link_ping_interval = link_ping_interval if link_ping_timeout_def: svr.link_ping_timeout = link_ping_timeout if onc_hostname_def: svr.onc_hostname = onc_hostname if max_clients_def: svr.max_clients = max_clients if replica_count_def: svr.replica_count = replica_count if dns_mapping_def: svr.dns_mapping = dns_mapping if debug_def: svr.debug = debug if svr.network_mode == BRIDGE: if not _check_network_range(svr.network, svr.network_start, svr.network_end): return utils.jsonify({ 'error': BRIDGE_NETWORK_INVALID, 'error_msg': BRIDGE_NETWORK_INVALID_MSG, }, 400) if svr.ipv6: return utils.jsonify({ 'error': IPV6_BRIDGED_INVALID, 'error_msg': IPV6_BRIDGED_INVALID_MSG, }, 400) if svr.links and svr.replica_count > 1: return utils.jsonify({ 'error': SERVER_LINKS_AND_REPLICA, 'error_msg': SERVER_LINKS_AND_REPLICA_MSG, }, 400) svr.commit(svr.changed) logger.LogEntry(message='Created server "%s".' % svr.name) event.Event(type=SERVERS_UPDATED) event.Event(type=SERVER_ROUTES_UPDATED, resource_id=svr.id) for org in svr.iter_orgs(): event.Event(type=USERS_UPDATED, resource_id=org.id) return utils.jsonify(svr.dict())
def main(default_conf=None): if len(sys.argv) > 1: cmd = sys.argv[1] else: cmd = 'start' parser = optparse.OptionParser(usage=USAGE) if cmd == 'start': parser.add_option('-d', '--daemon', action='store_true', help='Daemonize process') parser.add_option('-p', '--pidfile', type='string', help='Path to create pid file') parser.add_option('-c', '--conf', type='string', help='Path to configuration file') parser.add_option('-q', '--quiet', action='store_true', help='Suppress logging output') elif cmd == 'logs': parser.add_option('--archive', action='store_true', help='Archive log file') parser.add_option('--tail', action='store_true', help='Tail log file') parser.add_option('--limit', type='int', help='Limit log lines') parser.add_option('--natural', action='store_true', help='Natural log sort') elif cmd == 'set': parser.disable_interspersed_args() (options, args) = parser.parse_args() if hasattr(options, 'conf') and options.conf: conf_path = options.conf else: conf_path = default_conf pritunl.set_conf_path(conf_path) if cmd == 'version': print('%s v%s' % (pritunl.__title__, pritunl.__version__)) sys.exit(0) elif cmd == 'setup-key': from pritunl import setup from pritunl import settings setup.setup_loc() print(settings.local.setup_key) sys.exit(0) elif cmd == 'reset-version': from pritunl.constants import MIN_DATABASE_VER from pritunl import setup from pritunl import utils setup.setup_db() utils.set_db_ver(pritunl.__version__, MIN_DATABASE_VER) time.sleep(.2) print('Database version reset to %s' % pritunl.__version__) sys.exit(0) elif cmd == 'reset-password': from pritunl import setup from pritunl import auth setup.setup_db() username, password = auth.reset_password() print('Administrator password successfully reset:\n' + \ ' username: "******"\n password: "******"' % (username, password)) sys.exit(0) elif cmd == 'default-password': from pritunl import setup from pritunl import auth setup.setup_db() username, password = auth.get_default_password() if not password: print('No default password available, use reset-password') else: print('Administrator default password:\n' + \ ' username: "******"\n password: "******"' % (username, password)) sys.exit(0) elif cmd == 'reconfigure': from pritunl import setup from pritunl import settings setup.setup_loc() settings.conf.mongodb_uri = None settings.conf.commit() time.sleep(.2) print('Database configuration successfully reset') sys.exit(0) elif cmd == 'get': from pritunl import setup from pritunl import settings setup.setup_db_host() if len(args) != 2: raise ValueError('Invalid arguments') split = args[1].split('.') key_str = None group_str = split[0] if len(split) > 1: key_str = split[1] if group_str == 'host': group = settings.local.host else: group = getattr(settings, group_str) if key_str: val = getattr(group, key_str) print('%s.%s = %s' % (group_str, key_str, json.dumps(val, default=lambda x: str(x)))) else: for field in group.fields: val = getattr(group, field) print('%s.%s = %s' % (group_str, field, json.dumps(val, default=lambda x: str(x)))) sys.exit(0) elif cmd == 'set': from pritunl.constants import HOSTS_UPDATED from pritunl import setup from pritunl import settings from pritunl import event from pritunl import messenger setup.setup_db_host() if len(args) != 3: raise ValueError('Invalid arguments') group_str, key_str = args[1].split('.') if group_str == 'host': group = settings.local.host else: group = getattr(settings, group_str) val_str = args[2] try: val = json.loads(val_str) except ValueError: val = json.loads(json.JSONEncoder().encode(val_str)) setattr(group, key_str, val) if group_str == 'host': settings.local.host.commit() event.Event(type=HOSTS_UPDATED) messenger.publish('hosts', 'updated') else: settings.commit() time.sleep(.2) print('%s.%s = %s' % (group_str, key_str, json.dumps(getattr(group, key_str), default=lambda x: str(x)))) print('Successfully updated configuration. This change is ' \ 'stored in the database and has been applied to all hosts ' \ 'in the cluster.') sys.exit(0) elif cmd == 'unset': from pritunl import setup from pritunl import settings setup.setup_db() if len(args) != 2: raise ValueError('Invalid arguments') group_str, key_str = args[1].split('.') group = getattr(settings, group_str) group.unset(key_str) settings.commit() time.sleep(.2) print('%s.%s = %s' % (group_str, key_str, json.dumps(getattr(group, key_str), default=lambda x: str(x)))) print('Successfully updated configuration. This change is ' \ 'stored in the database and has been applied to all hosts ' \ 'in the cluster.') sys.exit(0) elif cmd == 'set-mongodb': from pritunl import setup from pritunl import settings setup.setup_loc() if len(args) > 1: mongodb_uri = args[1] else: mongodb_uri = None settings.conf.mongodb_uri = mongodb_uri settings.conf.commit() time.sleep(.2) print('Database configuration successfully set') sys.exit(0) elif cmd == 'reset-ssl-cert': from pritunl import setup from pritunl import settings setup.setup_db() settings.app.server_cert = None settings.app.server_key = None settings.app.acme_timestamp = None settings.app.acme_key = None settings.app.acme_domain = None settings.commit() time.sleep(.2) print('Server ssl certificate successfully reset') sys.exit(0) elif cmd == 'destroy-secondary': from pritunl import setup from pritunl import logger from pritunl import mongo setup.setup_db() print('Destroying secondary database...') mongo.get_collection('clients').drop() mongo.get_collection('clients_pool').drop() mongo.get_collection('transaction').drop() mongo.get_collection('queue').drop() mongo.get_collection('tasks').drop() mongo.get_collection('messages').drop() mongo.get_collection('users_key_link').drop() mongo.get_collection('auth_sessions').drop() mongo.get_collection('auth_csrf_tokens').drop() mongo.get_collection('auth_limiter').drop() mongo.get_collection('otp').drop() mongo.get_collection('otp_cache').drop() mongo.get_collection('sso_tokens').drop() mongo.get_collection('sso_push_cache').drop() mongo.get_collection('sso_client_cache').drop() mongo.get_collection('sso_passcode_cache').drop() setup.upsert_indexes() server_coll = mongo.get_collection('servers') server_coll.update_many({}, { '$set': { 'status': 'offline', 'instances': [], 'instances_count': 0, }, '$unset': { 'network_lock': '', 'network_lock_ttl': '', }, }) print('Secondary database destroyed') sys.exit(0) elif cmd == 'repair-database': from pritunl import setup from pritunl import logger from pritunl import mongo setup.setup_db() print('Repairing database...') mongo.get_collection('clients').drop() mongo.get_collection('clients_pool').drop() mongo.get_collection('transaction').drop() mongo.get_collection('queue').drop() mongo.get_collection('tasks').drop() mongo.get_collection('messages').drop() mongo.get_collection('users_key_link').drop() mongo.get_collection('auth_sessions').drop() mongo.get_collection('auth_csrf_tokens').drop() mongo.get_collection('auth_limiter').drop() mongo.get_collection('otp').drop() mongo.get_collection('otp_cache').drop() mongo.get_collection('sso_tokens').drop() mongo.get_collection('sso_push_cache').drop() mongo.get_collection('sso_client_cache').drop() mongo.get_collection('sso_passcode_cache').drop() mongo.get_collection('logs').drop() mongo.get_collection('log_entries').drop() mongo.get_collection('servers_ip_pool').drop() setup.upsert_indexes() server_coll = mongo.get_collection('servers') server_coll.update_many({}, { '$set': { 'status': 'offline', 'instances': [], 'instances_count': 0, }, '$unset': { 'network_lock': '', 'network_lock_ttl': '', }, }) from pritunl import server for svr in server.iter_servers(): try: svr.ip_pool.sync_ip_pool() except: logger.exception( 'Failed to sync server IP pool', 'tasks', server_id=svr.id, ) server_coll.update_many({}, { '$set': { 'status': 'offline', 'instances': [], 'instances_count': 0, }, '$unset': { 'network_lock': '', 'network_lock_ttl': '', }, }) print('Database repair complete') sys.exit(0) elif cmd == 'logs': from pritunl import setup from pritunl import logger setup.setup_db() log_view = logger.LogView() if options.archive: if len(args) > 1: archive_path = args[1] else: archive_path = './' print('Log archived to: ' + log_view.archive_log( archive_path, options.natural, options.limit)) elif options.tail: for msg in log_view.tail_log_lines(): print(msg) else: print( log_view.get_log_lines( natural=options.natural, limit=options.limit, )) sys.exit(0) elif cmd == 'clear-auth-limit': from pritunl import setup from pritunl import logger from pritunl import mongo from pritunl import settings setup.setup_db() mongo.get_collection('auth_limiter').delete_many({}) print('Auth limiter cleared') sys.exit(0) elif cmd == 'clear-logs': from pritunl import setup from pritunl import logger from pritunl import mongo from pritunl import settings setup.setup_db() mongo.get_collection('logs').drop() mongo.get_collection('log_entries').drop() prefix = settings.conf.mongodb_collection_prefix or '' log_limit = settings.app.log_limit mongo.database.create_collection(prefix + 'logs', capped=True, size=log_limit * 1024, max=log_limit) log_entry_limit = settings.app.log_entry_limit mongo.database.create_collection(prefix + 'log_entries', capped=True, size=log_entry_limit * 512, max=log_entry_limit) print('Log entries cleared') sys.exit(0) elif cmd != 'start': raise ValueError('Invalid command') from pritunl import settings if options.quiet: settings.local.quiet = True if options.daemon: pid = os.fork() if pid > 0: if options.pidfile: with open(options.pidfile, 'w') as pid_file: pid_file.write('%s' % pid) sys.exit(0) elif not options.quiet: print('##############################################################') print('# #') print('# /$$ /$$ /$$ #') print('# |__/ | $$ | $$ #') print('# /$$$$$$ /$$$$$$ /$$ /$$$$$$ /$$ /$$ /$$$$$$$ | $$ #') print('# /$$__ $$ /$$__ $$| $$|_ $$_/ | $$ | $$| $$__ $$| $$ #') print('# | $$ \ $$| $$ \__/| $$ | $$ | $$ | $$| $$ \ $$| $$ #') print('# | $$ | $$| $$ | $$ | $$ /$$| $$ | $$| $$ | $$| $$ #') print('# | $$$$$$$/| $$ | $$ | $$$$/| $$$$$$/| $$ | $$| $$ #') print('# | $$____/ |__/ |__/ \____/ \______/ |__/ |__/|__/ #') print('# | $$ #') print('# | $$ #') print('# |__/ #') print('# #') print('##############################################################') pritunl.init_server()
def sso_callback_get(): sso_mode = settings.app.sso if sso_mode not in (GOOGLE_AUTH, GOOGLE_DUO_AUTH, SLACK_AUTH, SLACK_DUO_AUTH, SAML_AUTH, SAML_DUO_AUTH, SAML_OKTA_AUTH, SAML_OKTA_DUO_AUTH, SAML_ONELOGIN_AUTH, SAML_ONELOGIN_DUO_AUTH): return flask.abort(405) state = flask.request.args.get('state') sig = flask.request.args.get('sig') tokens_collection = mongo.get_collection('sso_tokens') doc = tokens_collection.find_and_modify(query={ '_id': state, }, remove=True) if not doc: return flask.abort(404) query = flask.request.query_string.split('&sig=')[0] test_sig = base64.urlsafe_b64encode(hmac.new(str(doc['secret']), query, hashlib.sha512).digest()) if sig != test_sig: return flask.abort(401) params = urlparse.parse_qs(query) if doc.get('type') == SAML_AUTH: username = params.get('username')[0] email = params.get('email', [None])[0] org_name = params.get('org', [None])[0] if not username: return flask.abort(406) valid, org_name = sso.verify_saml(username, email, org_name) if not valid: return flask.abort(401) org_id = settings.app.sso_org if org_name: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id elif doc.get('type') == SLACK_AUTH: username = params.get('username')[0] email = None user_team = params.get('team')[0] org_names = params.get('orgs', [''])[0] org_names = org_names.split(',') valid, org_name = sso.verify_slack(username, user_team, org_names) if not valid: return flask.abort(401) if org_name: org_names = [org_name] org_id = settings.app.sso_org for org_name in org_names: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id break else: username = params.get('username')[0] email = username valid, org_name = sso.verify_google(username) if not valid: return flask.abort(401) org_id = settings.app.sso_org if org_name: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id if DUO_AUTH in sso_mode: valid, _ = sso.auth_duo( username, ipaddr=flask.request.remote_addr, type='Key', ) if not valid: return flask.abort(401) org = organization.get_by_id(org_id) if not org: return flask.abort(405) usr = org.find_user(name=username) if not usr: usr = org.new_user(name=username, email=email, type=CERT_CLIENT, auth_type=sso_mode) usr.audit_event('user_created', 'User created with single sign-on', remote_addr=utils.get_remote_addr()) event.Event(type=ORGS_UPDATED) event.Event(type=USERS_UPDATED, resource_id=org.id) event.Event(type=SERVERS_UPDATED) else: if usr.disabled: return flask.abort(403) if usr.auth_type != sso_mode: usr.auth_type = sso_mode usr.commit('auth_type') key_link = org.create_user_key_link(usr.id, one_time=True) usr.audit_event('user_profile', 'User profile viewed from single sign-on', remote_addr=utils.get_remote_addr(), ) return utils.redirect(utils.get_url_root()[:-1] + key_link['view_url'])
def sso_authenticate_post(): if settings.app.sso != DUO_AUTH: return flask.abort(405) username = flask.request.json['username'] usernames = [username] email = None if '@' in username: email = username usernames.append(username.split('@')[0]) valid = False for i, username in enumerate(usernames): try: valid, org_id = sso.auth_duo( username, strong=True, ipaddr=flask.request.remote_addr, type='Key', ) break except InvalidUser: if i == len(usernames) - 1: logger.error('Invalid duo username', 'sso', username=username, ) if not valid: logger.error('Invalid duo username', 'sso', username=username, ) return flask.abort(401) if not org_id: org_id = settings.app.sso_org org = organization.get_by_id(org_id) if not org: logger.error('Organization for Duo sso does not exist', 'sso', org_id=org_id, ) return flask.abort(405) usr = org.find_user(name=username) if not usr: usr = org.new_user(name=username, email=email, type=CERT_CLIENT, auth_type=DUO_AUTH) usr.audit_event('user_created', 'User created with single sign-on', remote_addr=utils.get_remote_addr()) event.Event(type=ORGS_UPDATED) event.Event(type=USERS_UPDATED, resource_id=org.id) event.Event(type=SERVERS_UPDATED) else: if usr.disabled: return flask.abort(403) if usr.auth_type != DUO_AUTH: usr.auth_type = DUO_AUTH usr.commit('auth_type') event.Event(type=USERS_UPDATED, resource_id=org.id) key_link = org.create_user_key_link(usr.id, one_time=True) usr.audit_event('user_profile', 'User profile viewed from single sign-on', remote_addr=utils.get_remote_addr(), ) return utils.get_url_root()[:-1] + key_link['view_url']
def user_key_pin_put(key_id): if settings.app.demo_mode: return utils.demo_blocked() doc = _find_doc({ 'key_id': key_id, }) if not doc: return flask.abort(404) if settings.app.demo_mode: return utils.demo_blocked() if settings.user.pin_mode == PIN_DISABLED: return utils.jsonify({ 'error': PIN_IS_DISABLED, 'error_msg': PIN_IS_DISABLED_MSG, }, 400) org = organization.get_by_id(doc['org_id']) usr = org.get_user(doc['user_id']) if usr.disabled: return flask.abort(403) if RADIUS_AUTH in usr.auth_type: return utils.jsonify({ 'error': PIN_RADIUS, 'error_msg': PIN_RADIUS_MSG, }, 400) current_pin = utils.filter_str( flask.request.json.get('current_pin')) or None pin = utils.filter_str(flask.request.json.get('pin')) or None if pin: if not pin.isdigit(): return utils.jsonify({ 'error': PIN_NOT_DIGITS, 'error_msg': PIN_NOT_DIGITS_MSG, }, 400) if len(pin) < settings.user.pin_min_length: return utils.jsonify({ 'error': PIN_TOO_SHORT, 'error_msg': PIN_TOO_SHORT_MSG, }, 400) if usr.pin and not usr.check_pin(current_pin): return utils.jsonify({ 'error': PIN_INVALID, 'error_msg': PIN_INVALID_MSG, }, 400) if usr.set_pin(pin): usr.audit_event('user_updated', 'User pin changed with temporary profile link', remote_addr=utils.get_remote_addr(), ) usr.commit() event.Event(type=USERS_UPDATED, resource_id=org.id) return utils.jsonify({})
def org_post(): name = utils.filter_str(flask.request.json['name']) org = organization.new_org(name=name, type=ORG_DEFAULT) logger.LogEntry(message='Created new organization "%s".' % org.name) event.Event(type=ORGS_UPDATED) return utils.jsonify(org.dict())