Пример #1
0
def ccs_init():
    global monitor_prefs, realm
    
    registerMenu(MENU_TOP, "%HOSTNAME%")
    registerMenu(MENU_BOTTOM, "External Links")
    registerMenuItem(MENU_TOP, MENU_GROUP_HOME, "/", "CPE Homepage")
    registerMenuItem(MENU_TOP, MENU_GROUP_CONTACT, "/contact", \
            "Contact Details")
    
    # Other modules can override these as necessary in ccs_init
    registerMenuItem(MENU_BOTTOM, MENU_GROUP_GENERAL, \
            "http://www.crc.net.nz/", "CRCnet Homepage")
    registerMenuItem(MENU_BOTTOM, MENU_GROUP_GENERAL, \
            "http://www.google.com/", "Google")

    resourcedir = config_get("www", "resourcedir", DEFAULT_RESOURCE_DIR)
    registerDir("/resources", resourcedir)

    # Initialise preferences store
    preffile = config_get("www", "preferences", DEFAULT_PREF_FILE)
    try:
        ensureFileExists(preffile)
        monitor_prefs = init_pref_store(preffile)
    except:
        log_fatal("Unable to initialise preference store: %s" % preffile, \
                sys.exc_info())

    realm = {"authenticator":loginForm, "users":{}, \
            "default_username":ADMIN_USERNAME}
    adminpass = pref_get(None, "admin_password", monitor_prefs, \
            DEFAULT_ADMIN_PASS)
    realm["users"][ADMIN_USERNAME] = adminpass
    registerRealm(CPE_ADMIN_REALM, realm)
Пример #2
0
def ccs_init():
    global debug_snmp
    # Default SNMP Content Helpers
    
    # Implement the basics of the SNMPv2-MIB
    SNMPv2_MIB = (1,3,6,1,2,1,1)
    registerStaticOID(SNMPv2_MIB+(1,0), "CRCnet Monitor v%s (r%s), %s" % \
            (ccsd_version, ccsd_revision, " ".join(os.uname())), "OctetString")

    # sysObjectID not implemented

    UPTIME_START = time.time()
    @registerDynamicOID(SNMPv2_MIB+(3,0))
    def uptime(oid, getNext):
        if getNext: return None
        uptime = (time.time()-UPTIME_START)*100
        return (oid, TimeTicks(uptime))

    # sysContact not implemented
    registerStaticOID(SNMPv2_MIB+(5,0), socket.gethostname(), "OctetString")
    # sysLocation not implemented
    # sysServices not implemented
    # sysOR not implemented
    
    # Start the actual SNMP server
    try:
        debug_snmp = config_getboolean("snmp", "debug", False)
        port = int(config_get("snmp", "port", DEFAULT_SNMP_PORT))
        AsyncSNMPServer(('', port))
        log_info("SNMP Server Started")
    except:
        log_fatal("Could not initialise the SNMP server!", sys.exc_info())
Пример #3
0
def homepage(request, method):
    
    
    # MOTD at the top
    liveMOTD = config_getboolean("www", "liveMOTD", False)
    homepage = config_get("www", "motdHomepage", "http://www.crc.net.nz")
    if liveMOTD:
        output = """<div class="content" id="motd">"""
        output += "<h2>Loading Latest News...</h2><br />"
        output += "Please wait while the latest news is retrieved."
    else:
        output = """<div class="content">"""
        output += "<h2>Latest News</h2><br />"
        output += "To keep up to date with the latest news "
        output += "please visit the homepage at "
        output += """<a href="%s">%s</a>""" % (homepage, homepage)
    output += "</div>"

    # Try and load the status summary from the status module
    try:
        from crcnetd.modules.ccs_monitor_status import getStatusSummary
        status = getStatusSummary()
    except:
        log_warn("Could not retrieve status summary", sys.exc_info())
        status = "CPE Status not available"
	
    # CPE Status
    output += """<div class="content">
<h2>CPE Status</h2><br />
%s
</div>
""" % status

    returnPage(request, "CPE Navigation", output, 
            scripts=["/resources/homepage.js"])
Пример #4
0
def statusThread():
    """Runs as a thread to keep the status information up to date"""
    global _statusInfo, _runStatus

    try:
        # Is status checking enabled
        enabled = config_getboolean("status", "enabled", True)
        if not enabled:
            log_info("Status checking disabled. Exiting status monitor thread")
            return
        _runStatus = True;

        # Setup the thread information 
        ct = threading.currentThread()
        ct.setName("CCSD Status Monitor")

        # What interval shall we check hosts at
        interval = config_get("status", "interval", DEFAULT_CHECK_INTERVAL)
        
        # Initialise the host status information
        hosts = getHostList(ADMIN_SESSION_ID)
        for host in getHostList(ADMIN_SESSION_ID):
            if not host["host_active"]:
                continue
            name = host["host_name"]
            _statusInfo[name] = ccs_host_status(ADMIN_SESSION_ID, \
                    host["host_id"], interval)
        
        # Loop forever reading status as appropriate
        while _runStatus:
            # wait a bit before checking
            time.sleep(2)
            # Does the queue have entries
            if len(ccs_host_status.update_queue) <= 0:
                continue
            # Is the first entry valid
            if len(ccs_host_status.update_queue[0]) != 2:
                log_error("Invalid entry in status update queue! - %s" %
                        ccs_host_status.update_queue[0])
                ccs_host_status.update_queue.pop(0)
                continue
            # Check if it's ready to run
            if ccs_host_status.update_queue[0][0] > time.time():
                continue
            # Read to run
            check = ccs_host_status.update_queue.pop(0)
            try:
                check[1].update()
            except:
                log_error("Failed to update status of %s" % \
                        check[1]._hostname, sys.exc_info())
            # Regardless of what happened, check again sometime soon if it
            # is still in the list of hosts to check
            if check[1]._hostname in _statusInfo.keys():
                check[1].requeue()
    except:
        log_error("Exception in status monitor thread!", sys.exc_info())

    log_info("Exiting status monitor thread")
Пример #5
0
def ts_chargei():
    ci_max = portname = config_get("status", "charge_i_max", DEFAULT_CI_MAX)
    for i in range(0,2):
        d=ts_readreg(TS_CHARGE_I_F)
        d*=66.667/32768
        if d <= ci_max:
            return d*1000
    return 0
Пример #6
0
def ts_arrayv():
    av_max = portname = config_get("status", "array_v_max", DEFAULT_AV_MAX)
    for i in range(0,2):
        d=ts_readreg(TS_ARRAY_V_F)
        d*=139.15/32768
        if d <= av_max:
            return d*1000
    return 0
Пример #7
0
def init_serial():
    """Initialises the serial port and connects to the tristar"""

    portname = config_get("status", "tristar_port", DEFAULT_TRISTAR_PORT)

    # Open the port
    p=[1, 0, 2301, 0, 13, 13]
    tty = SerialPort(portname, timeout=100, speed=9600, mode="232", params=p)

    return tty
Пример #8
0
def init_ca():
    """Called during server startup to initialise the CA environment
    
    The CA must not be initialised until after the cfengine module so that the
    subversion repository is ready to use
    """
    global certParams
    
    # Load the repository to check for a CA
    session_id = ADMIN_SESSION_ID
    session = getSession(session_id)
    changeset = session.changeset
                      
    revision = ccs_revision(session, changeset);
 
    #If the CA does not exist, make it and add it to the repository
    if not revision.fileExists("ca/cacert.pem"):
        log_info("Creating CA for the certificates")
        siteName = config_get("network","site_name")
        if siteName == "":
            siteName = "CRCnet Default Site"
        wDir = revision.getWorkingDir()
        (fdi, fdo) = os.popen2("openssl req -new -x509 -nodes -keyout "\
            "%s/ca/cakey.pem -out %s/ca/cacert.pem -days 3650 2>&1"\
             % (wDir,wDir))
        fdi.write("NZ\n") #country
        fdi.write(".\n")  #ignore state of province
        fdi.write(".\n")  #ignore location
        fdi.write("%s\n" % siteName) #Organisation
        fdi.write("ccsd\n") #Organisation Unit
        fdi.write("Certification Authority\n") #Common Name
        fdi.write(".\n")  #ignore email
        fdo.close()
        fdi.close()
        time.sleep(1)
        revision.checkin("Added CA", ["%s/ca/cacert.pem" % (wDir),\
            "%s/ca/cakey.pem" % (wDir)])
    
    # Load the CA
    try:
        ca = ccs_ca()
        certParams = ca.getCAParameters()
    except ccs_ca_error:
        (type, value, tb) = sys.exc_info()
        log_fatal("CA: Unable to initialise: %s" % value, \
                (type, value, tb))
    
    # Ensure there is a server key, and a client key for the web interface
    # and the pxeboot scripts
    for name in ["server", "ccsweb", "pxe-scripts"]:
        if not ca.ensureCertificateExists(name):
            log_fatal("CA: %s is a required key. Exiting!" % name)
Пример #9
0
def returnPage(request, title, content, menuadd=None, scripts=[], styles=[]):
    """Returns a basic HTML page using the default template.

    title   - The desired page title
    content - An HTML blob to populate the content area of the page
    menuadd - An HTML blob to append to the end of the generated menus

    The template must allow substitution of the tokens %TITLE%,
    %CONTENT%, %MENU%, %SCRIPTS%, %STYLES% in the appropriate places.
    """

    # Get the template
    resourcedir = config_get("www", "resourcedir", DEFAULT_RESOURCE_DIR)
    tfile = "%s/page.html" % resourcedir
    try:
        fd = open(tfile, "r")
        template = fd.read()
        fd.close()
    except:
        log_error("Page template not available!", sys.exc_info())
        # Return a very cruddy basic page
        template = "<html><head><title>%TITLE%</title></head>" \
                "<body><h2>Menu</h2><br />%MENU%<br /><hr />" \
                "<h2>%TITLE%</h2><br />%CONTENT%</body></html>"
        
    # Substitute as necessary
    menustr = buildMenu()
    if menuadd is not None:
        menustr += menuadd
    scriptstr = stylestr = ""
    for script in scripts:
        scriptstr += """<script type="text/javascript" src="%s">""" \
                "</script>\n""" % script
    for style in styles:
        stylestr += """<link rel="stylesheet" type="text/css" src="%s""" \
                " />\n""" % style
    footer = "Page generated at: %s" % time.ctime()
    ip = getIfaceIPForIP(request.client_address[0])
    if ip == "":
        ip = request.headers.get("Host").strip()
    host = "http://%s" % ip
    output = template.replace("%SCRIPTS%", scriptstr).replace("%STYLES%", \
            stylestr).replace("%TITLE%", title).replace("%MENU%", \
            menustr).replace("%CONTENT%", content).replace("%FOOTER%", \
            footer).replace("%HOST%", host)
    
    # Send it away
    request.send_response(200)
    request.end_headers()
    request.wfile.write(output)
    request.finish()
Пример #10
0
def addHostStatus(eventName, host_id, session_id, **params):
    """New host needs to be added to the monitor"""
    global _statusInfo, _runStatus

    #Only add if thread is running
    if _runStatus:
        host = ccs_host(session_id, host_id)
        name = host["host_name"]

        #Only add if host is active and not already in the list
        if host._properties["host_active"] and name not in _statusInfo:
            interval = config_get("status", "interval", DEFAULT_CHECK_INTERVAL)
            _statusInfo[name] = ccs_host_status(ADMIN_SESSION_ID, \
                host_id, interval)
Пример #11
0
def contactpage(request, method):
    
    output = ""
    
    # Get the template
    resourcedir = config_get("www", "resourcedir", DEFAULT_RESOURCE_DIR)
    tfile = "%s/contact.html" % resourcedir
    try:
        fd = open(tfile, "r")
        details = fd.read()
        fd.close()
    except:
        log_error("Contact HTML not available!", sys.exc_info())
        # Return a very cruddy basic page
        details = "No contact details available!"
        
    output += """<div class="content">%s</div>""" % details

    returnPage(request, "Contact Details", output)
Пример #12
0
    def initConfFile(self):
        """Initialises the CA configuration file"""
        
        signdays = config_get("ca", "signdays", DEFAULT_SIGN_DAYS)
        site_name = config_get_required("network", "site_name")
        domain = config_get_required("network", "domain")
        
        fd = open("%s/ca.cnf" % self.rDir, "w")
        fd.write("""#
# OpenSSL configuration file for the CRCnet Configuration System CA

# This definition stops the following lines choking if HOME isn't
# defined.
HOME                    = .
RANDFILE                = $ENV::HOME/.rnd

####################################################################
[ ca ]
default_ca              = CA_default            # The default ca section

####################################################################
[ CA_default ]

dir                 = $ENV::CCS_CA_DIR      # Where everything is kept
certs               = $dir/certs            # Where the issued certs are kept
crl_dir             = $dir/crl              # Where the issued crl are kept
database            = $dir/index.txt        # database index file.
new_certs_dir       = $dir/certs            # default place for new certs.

certificate         = $dir/cacert.pem       # The CA certificate
private_key         = $dir/cakey.pem        # The private key
serial              = $dir/serial           # The current serial number
crlnumber           = $dir/crlnumber        # the current crl number
crl                 = $dir/crl.pem          # The current CRL
RANDFILE            = $dir/.rand            # private random number file

x509_extensions     = usr_cert              # The extentions to add to the cert
name_opt            = ca_default            # Subject Name options
cert_opt            = ca_default            # Certificate field options

default_days        = %s                    # how long to certify for
default_crl_days    = 30                    # how long before next CRL
default_md          = sha1                  # which md to use.
preserve            = no                    # keep passed DN ordering

policy          = policy_match

# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = optional
localityName            = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

####################################################################
[ req ]
default_bits            = 1024
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions         = v3_ca  # Extensions to add to self signed certs
string_mask = nombstr

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = NZ
countryName_min                 = 2
countryName_max                 = 2

localityName                    = Locality Name (eg, city)

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = %s

organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default  = CRCnet Configuration System

commonName                      = Common Name (eg, YOUR name)
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_max                = 64

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20

unstructuredName                = An optional company name

# These extensions are added when 'ca' signs a request.
[ usr_cert ]
basicConstraints                = CA:FALSE

# nsCertType                    = server
# nsCertType                    = client

# This will be displayed in Netscape's comment listbox.
nsComment                       = "Signed by the CRCnet Configuration System"

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer

nsRevocationUrl                 = https://%s/certs/crl.pem

# Extensions to add to a certificate request
[ v3_req ]
basicConstraints        = CA:FALSE
keyUsage                = nonRepudiation, digitalSignature, keyEncipherment

# Extensions for a typical CA
[ v3_ca ]
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
basicConstraints        = CA:true

# CRL extensions.
[ crl_ext ]
authorityKeyIdentifier  = keyid:always,issuer:always
""" % (signdays, site_name, domain))
        fd.close()
        client.svn_client_add("%s/ca.cnf" % self.rDir, False, \
                    self.ctx, self.pool)
        log_info("CA: Initialised configuration file")
        return
Пример #13
0
def ifAccountThread():
    """Runs as a thread to account from traffic on an interface"""
    global _accountingInfo, _runIfAccount, nas_id, nas_ip
    global radius_update_interval, radius_acct_server, radius_auth_server

    try:
        # Is interface accounting enabled
        enabled = config_getboolean("accounting", "enabled", True)
        if not enabled:
            log_info("Interface accounting disabled.")
            return
        _runIfAccount = True

        # What interval shall we check hosts at
        check_interval = config_get("accounting", "check_interval", DEFAULT_CHECK_INTERVAL)
        radius_update_interval = config_getint("accounting", "update_interval", DEFAULT_UPDATE_INTERVAL)

        # Initialise the interface list
        default_user_file = "%s/accounting_users" % os.path.dirname(DEFAULT_CONFFILE)
        user_file = config_get("accounting", "user_file", default_user_file)
        if not os.path.exists(user_file):
            log_error("Interface accounting disabled. No user file: %s" % user_file)
            _runIfAccount = False
            return

        # Initialise the RADIUS connection
        try:
            dummy0 = getInterfaces(returnOne="dummy0")[0]
            dummy0ip = dummy0["address"].split("/")[0]
        except:
            log_error("Could not determine host loopback address!", sys.exc_info())
            dummy0ip = "127.0.0.1"
        acct_server = config_get("accounting", "acct_server", "radius")
        acct_secret = config_get_required("accounting", "acct_secret")
        auth_server = config_get("accounting", "auth_server", "radius")
        auth_secret = config_get_required("accounting", "auth_secret")
        nas_id = config_get("accounting", "nas_id", getFQDN())
        nas_ip = config_get("accounting", "nas_ip", dummy0ip)
        radius_acct_server = Client(server=acct_server, secret=acct_secret, dict=Dictionary(RADIUS_DICTIONARY))
        radius_auth_server = Client(server=auth_server, secret=auth_secret, dict=Dictionary(RADIUS_DICTIONARY))
        # FreeRADIUS at least auths based on IP address, make sure our
        # packets come from the right place
        radius_acct_server.bind((nas_ip, 0))
        radius_auth_server.bind((nas_ip, 0))

        # Read and parse the user file
        parseUserFile(user_file)

        # Initialise interface state
        initialiseInterfaceState()

        # Loop forever reading byte counters as appropriate
        while _runIfAccount:
            # wait a bit before checking
            time.sleep(check_interval)
            # Send any queued packets
            processRADIUSQueue()
            # Try and re-authenticate any dead interfaces
            for ifname, iface in _accountingInfo.items():
                if iface["authenticated"]:
                    continue
                age = time.time() - iface["last_auth_check"]
                if age > radius_update_interval:
                    doRADIUSAuthentication(ifname)
            # Update traffic details
            updateTrafficCounters()
            # Generate interim-updates
            processInterimUpdates()

    except:
        (etype, value, tb) = sys.exc_info()
        log_error("Exception in interface accounting thread! - %s" % value, (etype, value, tb))

    log_info("Exiting interface accounting thread")
Пример #14
0
def getMOTD(request, method):
    """Returns HTML to display the Message of the Day"""
    
    tmpdir = config_get(None, "tmpdir", DEFAULT_TMPDIR)
    motdFile = "%s/motd" % tmpdir
    motdRefreshInterval = config_get("www", "motd_refresh", \
            DEFAULT_MOTD_REFRESH)
    motdURL = config_get("www", "motdURL", DEFAULT_MOTD_URL)
    fetchMotd = config_getboolean("www", "fetch_motd", False)
    updateNote = ""
    
    try:
        mtime = os.stat(motdFile)[8]
    except:
        mtime = -1

    if (mtime == -1 or time.time()-mtime > motdRefreshInterval or \
            request.query.find("refreshMotd=true") != -1) and fetchMotd:
        # Get new MOTD
        try:
            o = urllib.URLopener()
            o.addheaders = [("User-agent", "crcnet-monitor/%s (r%s)" % \
                    (ccsd_version, ccsd_revision))]
            wfd = o.open(motdURL)
            fd = open(motdFile, "w")
            motd = wfd.read()
            fd.write(motd)
            fd.close
            wfd.close()
            mtime = time.time()
        except:
            log_error("Unable to fetch MOTD", sys.exc_info())
            motd = "Unable to retrieve latest news."
            mtime = -1
    else:
        try:
            fd = open(motdFile, "r")
            motd = fd.read()
            fd.close()
        except:
            motd = "No news available"
        
    # Calculate how long till next update
    if mtime != -1:
        updateAtSecs = (mtime + motdRefreshInterval) - time.time()
        updateAt = formatTime(updateAtSecs)
        retrieved = time.ctime(mtime)
        updateNote = "Retrieved at %s, next update in %s" % (retrieved, updateAt)

    # Generate the output
    output = """<h2>Latest News <span class="note">%s&nbsp;
<a href="/?refreshMotd=true">[Refresh Now]</a>
</span>
</h2><br />
%s
""" % (updateNote, motd.replace("\n", "<br />"))

    length = len(output)
    request.send_response(200)
    request.send_header("Length", length)
    request.end_headers()
    request.wfile.write(output)
    request.finish()
    return