Example #1
0
def _update_graphs(quick=False):
    """Update RRD data and web UI graphs."""

    if os.path.exists(constants.LOWMEM_MARKER_FILE):
        _log.debug('lowmem marker exists, not updating graphs')
        return

    # measure and update rrd data
    g = graphs.Graphs()
    try:
        if helpers.check_marker_file(constants.TIMESYNC_TIMESTAMP_FILE) or \
           helpers.check_marker_file(constants.WEBUI_LAST_TIMESYNC_FILE):
            _log.debug('timesync ok, updating rrd')
            update_rrd = True
        else:
            # If rrdtool is updated with a future timestamp (say Jan 1, 2010) it will
            # refuse to update values in the 'past' (say Jan 1, 2007); so we only want
            # to run rrd updates if we do have a server-based timesync.
            _log.info('no timesync, not updating rrd information to avoid confusing rrdtool')
            update_rrd = False

        g.measure_and_update(update_rrd=update_rrd, update_rdf=True, quick=quick)
    except:
        _log.exception('measure_and_update() failed')

    # draw graphs required by web UI here, but only if it "makes a difference"
    try:
        if _check_draw_graph(constants.RRDGRAPH_USER_COUNT):
            g.draw_user_graph()
        else:
            _log.info('not drawing user graph on this cron run')
    except:
        _log.exception('draw_user_graph() failed')
    try:
        if _check_draw_graph(constants.RRDGRAPH_SITETOSITE_COUNT):
            g.draw_sitetosite_graph()
        else:
            _log.info('not drawing user graph on this cron run')
    except:
        _log.exception('draw_sitetosite_graph() failed')
Example #2
0
def _check_draw_graph(graph_file):
    """Check whether the specified graph file should be redrawn.

    Currently we use the following heuristic: (1) if graph is older than N
    minutes, redraw it;  (2) if admin has active session(s), redraw on every
    cron run (we detect this by ajax active timestamp).

    We could also redraw if an interesting parameter has changed (user or s2s
    count, license limits, timezones, etc).  But because these entail RRD accesses,
    we just use the simpler heuristic above.
    """

    now = datetime.datetime.utcnow()

    # consider ajax "off-line" if timestamp older than this (or negative)
    ajax_limit = datetime.timedelta(0, 5*60, 0)   # XXX: constants?

    # redraw graphs if graph age below zero or over limit below
    graph_zero = datetime.timedelta(0, 0, 0)
    graph_maxage = datetime.timedelta(0, 15*60, 0) # XXX: constants?
    
    if helpers.check_marker_file(constants.WEBUI_ADMIN_ACTIVE_TIMESTAMP):
        dt = helpers.read_datetime_marker_file(constants.WEBUI_ADMIN_ACTIVE_TIMESTAMP)
        diff = now - dt
        if diff < ajax_limit:
            # ajax active, draw
            _log.info('ajax active, redraw graph %s' % graph_file)
            return True
        else:
            # fall through, check graph file
            pass
        
    if os.path.exists(graph_file):
        mtime = datetime.datetime.utcfromtimestamp(os.stat(graph_file).st_mtime)
        diff = now - mtime
        if (diff < graph_zero) or (diff > graph_maxage):
            # bogus or too old, redraw
            _log.info('graph too old, redraw graph %s' % graph_file)
            return True
        else:
            _log.info('graph not too old, skipping redraw for %s' % graph_file)
            return False
        
    # no graph file, redraw always
    _log.info('graph does not exist, redraw graph %s' % graph_file)
    return True
Example #3
0
    def renderHTTP(self, ctx):
        # XXX: refactor this to a helper??
        def _xml_escape(x):
            return helpers.xml_escape(x)

        # XXX: simple base64 encoding does not seem to be enough
        def _base64_encode(x):
            # base64 produces a newline, strip it away; still not correct tho
            return x.encode('base64').strip()

        request = inevow.IRequest(ctx)

        # figure parameters
        server_address = ''
        try:
            server_address = str(request.getRequestHostname())
        except:
            _log.exception('cannot figure out server_address')

        preshared_key = ''
        try:
            psk_seq = helpers.get_ui_config().getS(
                ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey)))
            preshared_key = str(psk_seq[0].getS(ns_ui.preSharedKey,
                                                rdf.String))
        except:
            _log.exception('cannot figure out preshared_key')

        username = ''
        try:
            tmp = self.get_logged_in_username()
            if tmp is not None:
                username = str(tmp)
        except:
            _log.exception('cannot figure out username')

        # Profile name
        profile_prefix = 'VPNease'
        try:
            if os.path.exists(constants.AUTOCONFIG_PROFILE_PREFIX_FILE):
                profile_prefix = helpers.read_and_strip_file(
                    constants.AUTOCONFIG_PROFILE_PREFIX_FILE)
        except:
            _log.exception('failed when checking for alternative profile name')
        profile_name = '%s (%s)' % (profile_prefix, server_address)

        # Server behind port forward
        server_portfw = False
        try:
            global_st = helpers.get_global_status()
            if global_st.hasS(ns.behindNat):
                if global_st.getS(ns.behindNat, rdf.Boolean):
                    server_portfw = True
                else:
                    server_portfw = False
            else:
                # assume worst - reboot *MAY* be required
                server_portfw = True

            # markerfile for debugging
            if helpers.check_marker_file(
                    constants.FORCE_NATTREBOOT_MARKERFILE):
                _log.warning(
                    'force nat-t reboot marker file exists, pretending server is behind port forward'
                )
                server_portfw = True
        except:
            _log.exception(
                'cannot determine whether server is behind port forward, may be OK'
            )

        #
        #  Notes about OSX plist for networkConnect
        #
        #    * There are settings for PPP redial counts etc.  We don't use them
        #      because we want to minimize risks.
        #
        #    * DisconnectOnXXX settings only seem to work when inside SystemConfig,
        #      not inside UserConfigs.
        #
        #    * SystemConfig -> IPv4 -> OverridePrimary=1 should, based on PPP code,
        #      set 'default route' setting but doesn't seem to work.
        #
        #    * UserConfigs -> IPsec -> ExportedSharedSecret contains the pre-shared
        #      key for IKE in some sort of encrypted format.  The value is base64
        #      encoded but the pre-shared key is processed (encrypted or masked)
        #      prior to base64.  Note that whatever the unknown (and seemingly
        #      undocumented transform is, it has to be reversible because IKE needs
        #      the PSK.
        #
        #    * CCP / MPPC / MPPE are disabled now.  They don't actually work in
        #      Leopard at least.
        #

        # create xml plist
        textdata = textwrap.dedent("""\
            <?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
            <plist version="1.0">
                <dict>
                    <key>L2TP</key>
                    <dict>
                        <key>SystemConfig</key>
                        <dict>
                            <key>PPP</key>
                            <dict>
                                <key>DisconnectOnSleep</key>
                                <integer>1</integer>
                                <key>DisconnectOnFastUserSwitch</key>
                                <integer>1</integer>
                                <key>DisconnectOnLogout</key>
                                <integer>1</integer>
                            </dict>
                        </dict>

                        <key>UserConfigs</key>
                        <array>
                            <dict>
                                <key>EAP</key>
                                <dict/>
                                <key>IPSec</key>
                                <dict>
                                    <key>AuthenticationMethod</key>
                                    <string>SharedSecret</string>
                                    <key>LocalIdentifier</key>
                                    <string></string>
                                    <key>LocalIdentifierType</key>
                                    <string>KeyID</string>
                                </dict>
                                <key>PPP</key>
                                <dict>
                                    <key>AuthName</key>
                                    <string>%(username)s</string>
                                    <key>CommRemoteAddress</key>
                                    <string>%(server_address)s</string>
                                    <key>UserDefinedName</key>
                                    <string>%(profile_name)s</string>
                                    <key>CCPEnabled</key>
                                    <integer>%(ccp_enabled)d</integer>
                                    <key>CCPMPPE128Enabled</key>
                                    <integer>%(ccp_mppe40_enabled)d</integer>
                                    <key>CCPMPPE40Enabled</key>
                                    <integer>%(ccp_mppe128_enabled)d</integer>
                                </dict>
                            </dict>
                        </array>
                    </dict>
                </dict>
            </plist>
        """) % {
            'preshared_key_base64': _xml_escape(_base64_encode(preshared_key)),
            'username': _xml_escape(username),
            'server_address': _xml_escape(server_address),
            'profile_name': _xml_escape(profile_name),
            'override_primary': 1,  # XXX: force default route
            'ccp_enabled': 0,
            'ccp_mppe40_enabled': 0,
            'ccp_mppe128_enabled': 0,
        }

        #
        #  Content-Type is interesting.  If this is served as 'text/xml', Safari
        #  will display the file without offering a save option.  Even if it is
        #  saved, Safari will *refuse* saving the file with '.networkConnect'
        #  extension.
        #
        #  'application/octet-stream' causes Safari to save the file, and use can
        #  double click to run it.
        #

        return uihelpers.UncachedData(textdata, 'application/octet-stream')
Example #4
0
    def renderHTTP(self, ctx):
        # XXX: refactor this to a helper??
        def _xml_escape(x):
            return helpers.xml_escape(x)

        # XXX: simple base64 encoding does not seem to be enough
        def _base64_encode(x):
            # base64 produces a newline, strip it away; still not correct tho
            return x.encode('base64').strip()

        request = inevow.IRequest(ctx)

        # figure parameters
        server_address = ''
        try:
            server_address = str(request.getRequestHostname())
        except:
            _log.exception('cannot figure out server_address')
            
        preshared_key = ''
        try:
            psk_seq = helpers.get_ui_config().getS(ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey)))
            preshared_key = str(psk_seq[0].getS(ns_ui.preSharedKey, rdf.String))
        except:
            _log.exception('cannot figure out preshared_key')

        username = ''
        try:
            tmp = self.get_logged_in_username()
            if tmp is not None:
                username = str(tmp)
        except:
            _log.exception('cannot figure out username')
            
        # Profile name
        profile_prefix = 'VPNease'
        try:
            if os.path.exists(constants.AUTOCONFIG_PROFILE_PREFIX_FILE):
                profile_prefix = helpers.read_and_strip_file(constants.AUTOCONFIG_PROFILE_PREFIX_FILE)
        except:
            _log.exception('failed when checking for alternative profile name')
        profile_name = '%s (%s)' % (profile_prefix, server_address)

        # Server behind port forward
        server_portfw = False
        try:
            global_st = helpers.get_global_status()
            if global_st.hasS(ns.behindNat):
                if global_st.getS(ns.behindNat, rdf.Boolean):
                    server_portfw = True
                else:
                    server_portfw = False
            else:
                # assume worst - reboot *MAY* be required
                server_portfw = True

            # markerfile for debugging
            if helpers.check_marker_file(constants.FORCE_NATTREBOOT_MARKERFILE):
                _log.warning('force nat-t reboot marker file exists, pretending server is behind port forward')
                server_portfw = True
        except:
            _log.exception('cannot determine whether server is behind port forward, may be OK')
            
        #
        #  Notes about OSX plist for networkConnect
        #
        #    * There are settings for PPP redial counts etc.  We don't use them
        #      because we want to minimize risks.
        #
        #    * DisconnectOnXXX settings only seem to work when inside SystemConfig,
        #      not inside UserConfigs.
        #
        #    * SystemConfig -> IPv4 -> OverridePrimary=1 should, based on PPP code,
        #      set 'default route' setting but doesn't seem to work.
        #
        #    * UserConfigs -> IPsec -> ExportedSharedSecret contains the pre-shared
        #      key for IKE in some sort of encrypted format.  The value is base64
        #      encoded but the pre-shared key is processed (encrypted or masked)
        #      prior to base64.  Note that whatever the unknown (and seemingly
        #      undocumented transform is, it has to be reversible because IKE needs
        #      the PSK.
        #
        #    * CCP / MPPC / MPPE are disabled now.  They don't actually work in
        #      Leopard at least.
        #
        
        # create xml plist
        textdata = textwrap.dedent("""\
            <?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
            <plist version="1.0">
                <dict>
                    <key>L2TP</key>
                    <dict>
                        <key>SystemConfig</key>
                        <dict>
                            <key>PPP</key>
                            <dict>
                                <key>DisconnectOnSleep</key>
                                <integer>1</integer>
                                <key>DisconnectOnFastUserSwitch</key>
                                <integer>1</integer>
                                <key>DisconnectOnLogout</key>
                                <integer>1</integer>
                            </dict>
                        </dict>

                        <key>UserConfigs</key>
                        <array>
                            <dict>
                                <key>EAP</key>
                                <dict/>
                                <key>IPSec</key>
                                <dict>
                                    <key>AuthenticationMethod</key>
                                    <string>SharedSecret</string>
                                    <key>LocalIdentifier</key>
                                    <string></string>
                                    <key>LocalIdentifierType</key>
                                    <string>KeyID</string>
                                </dict>
                                <key>PPP</key>
                                <dict>
                                    <key>AuthName</key>
                                    <string>%(username)s</string>
                                    <key>CommRemoteAddress</key>
                                    <string>%(server_address)s</string>
                                    <key>UserDefinedName</key>
                                    <string>%(profile_name)s</string>
                                    <key>CCPEnabled</key>
                                    <integer>%(ccp_enabled)d</integer>
                                    <key>CCPMPPE128Enabled</key>
                                    <integer>%(ccp_mppe40_enabled)d</integer>
                                    <key>CCPMPPE40Enabled</key>
                                    <integer>%(ccp_mppe128_enabled)d</integer>
                                </dict>
                            </dict>
                        </array>
                    </dict>
                </dict>
            </plist>
        """) % {
            'preshared_key_base64': _xml_escape(_base64_encode(preshared_key)),
            'username': _xml_escape(username),
            'server_address': _xml_escape(server_address),
            'profile_name': _xml_escape(profile_name),
            'override_primary': 1, # XXX: force default route
            'ccp_enabled': 0,
            'ccp_mppe40_enabled': 0,
            'ccp_mppe128_enabled': 0,
            }
        
        #
        #  Content-Type is interesting.  If this is served as 'text/xml', Safari
        #  will display the file without offering a save option.  Even if it is
        #  saved, Safari will *refuse* saving the file with '.networkConnect'
        #  extension.
        #
        #  'application/octet-stream' causes Safari to save the file, and use can
        #  double click to run it.
        #

        return uihelpers.UncachedData(textdata, 'application/octet-stream')
Example #5
0
    def renderHTTP(self, ctx):
        request = inevow.IRequest(ctx)

        # read unpatched exe
        f = None
        exedata = ''
        try:
            f = open(self.autoconfig_exe_filename, 'rb')
            exedata = f.read()
        finally:
            if f is not None:
                f.close()
                f = None

        # figure parameters
        server_address_in_uri = None
        try:
            server_address_in_uri = str(request.getRequestHostname())
        except:
            _log.exception('cannot figure out server_address_in_uri')

        server_ip = None
        try:
            server_ip = self._get_server_ip_for_win2k(ctx)
        except:
            _log.exception('cannot figure out server_ip')

        server_address = None
        if self.force_server_address_to_ip:
            server_address = server_ip
        else:
            server_address = server_address_in_uri

        if (server_address_in_uri is None) or (server_address_in_uri == ''):
            raise Exception('server_address_in_uri missing, failing')
        if (server_address is None) or (server_address == ''):
            raise Exception('server_address missing, failing')
        if self.include_win2k_regdata and ((server_ip is None) or (server_ip == '')):
            raise Exception('server_ip is needed and missing, failing')
        
        preshared_key = ''
        try:
            psk_seq = helpers.get_ui_config().getS(ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey)))
            preshared_key = str(psk_seq[0].getS(ns_ui.preSharedKey, rdf.String))
        except:
            _log.exception('cannot figure out preshared_key')

        username = ''
        try:
            tmp = self.get_logged_in_username()
            if tmp is not None:
                username = str(tmp)
        except:
            _log.exception('cannot figure out username')
            
        # Profile name, always uses address in URI, even if server address itself forced to IP
        profile_prefix = 'VPNease'
        try:
            if os.path.exists(constants.AUTOCONFIG_PROFILE_PREFIX_FILE):
                profile_prefix = helpers.read_and_strip_file(constants.AUTOCONFIG_PROFILE_PREFIX_FILE)
        except:
            _log.exception('failed when checking for alternative profile name')
        profile_name = '%s (%s)' % (profile_prefix, server_address_in_uri)

        # Server behind port forward
        server_portfw = False
        try:
            global_st = helpers.get_global_status()
            if global_st.hasS(ns.behindNat):
                if global_st.getS(ns.behindNat, rdf.Boolean):
                    server_portfw = True
                else:
                    server_portfw = False
            else:
                # assume worst - reboot *MAY* be required
                server_portfw = True

            # markerfile for debugging
            if helpers.check_marker_file(constants.FORCE_NATTREBOOT_MARKERFILE):
                _log.warning('force nat-t reboot marker file exists, pretending server is behind port forward')
                server_portfw = True
        except:
            _log.exception('cannot determine whether server is behind port forward, may be OK')

        # Windows 2000 registry-based IPsec policy + prohibitIpsec
        win2k_ipsec_policy_registry_file = ''
        try:
            if self.include_win2k_regdata:
                # Registry data is HEX encoded UTF-16; HEX encoding is used to avoid problems
                # with the parameters.cpp mechanism (null termination).  The resulting data is
                # large, around 50 kilobytes (!).

                # Always uses server IP for IPsec policy, because that's what Windows 2000 IPsec wants
                t = self._get_win2k_reg_file(server_ip, preshared_key)
                t = self._encode_windows_reg_file(t)  # UTF-16
                win2k_ipsec_policy_registry_file = t.encode('hex')  # hex-encoded UTF-16
        except:
            _log.exception('cannot create win2k registry file')
        
        # Fill paramdict and return
        paramdict = {}
        paramdict['operation'] = 'configure_profile'
        paramdict['profile_name'] = profile_name
        paramdict['desktop_shortcut_name'] = '%s.LNK' % profile_name  # xxx: for now the same
        paramdict['server_address'] = server_address
        paramdict['preshared_key'] = preshared_key
        paramdict['username'] = username
        paramdict['ppp_compression_enabled'] = '1'
        paramdict['default_route_enabled'] = '1'
        paramdict['create_desktop_shortcut'] = '1'
        paramdict['open_profile_after_creation'] = '1'
        if server_portfw:
            paramdict['server_behind_port_forward'] = '1'
        else:
            paramdict['server_behind_port_forward'] = '0'
        if self.include_win2k_regdata:
            paramdict['win2k_registry_file'] = win2k_ipsec_policy_registry_file
        return uihelpers.RewritingBinaryResource(exedata, paramdict)