Example #1
0
 def roundDone(self, responses, key, x):
     self.debugpath.append("FV: roundDone %d" % x)
     if self.done:
         result = {}
         # see if everyone's responses agreed...
         for success, resp in responses:
             # only look at successful non-kData (dict) responses.
             if success and resp != None and not isinstance(resp, dict):
                 if result.has_key(resp):
                     result[resp] += 1
                 else:
                     result[resp] = 1
         if len(result) == 0:
             # ... if no one responded, XXX: do something orther than None?
             logger.info("couldn't get any results")
             return None
         elif len(result) == 1:
             # ... if they did, return the result
             return result.keys()[0]
         else:
             # ... otherwise, return the result of the majority
             # (other options include returning all results)
             logger.info("got conflicting results, determining best...")
             quorumResult = None
             bestScore = 0
             for r in result:
                 #logger.debug("result %s scored %d" % (r, result[r]))
                 if result[r] > bestScore:
                     bestScore = result[r]
                     quorumResult = r
                     #logger.debug("result %s is new best" % r)
             logger.info("returning result %s", fdecode(quorumResult))
             return quorumResult
Example #2
0
def listMeta(config):
    fmaster = open(os.path.join(config.metadir,config.metamaster), 'r')
    master = fmaster.read()
    fmaster.close()
    if master == "":
        master = {}
    else:
        master = fdecode(master)
    return master
Example #3
0
def getChallenge(challenge):
    try:
        challenge = fdecode(challenge)
    except:
        pass
    if outstandingChallenges.has_key(challenge):
        return outstandingChallenges[challenge]
    else:
        return None
Example #4
0
 def loadMasterMeta(self):
     """
     loads fname->sK mappings from file
     """
     fmaster = open(os.path.join(self.metadir, self.metamaster), 'r')
     master = fmaster.read()
     fmaster.close()
     if master == "":
         master = {}
     else:
         master = fdecode(master)
     self.master = master
Example #5
0
def answerChallenge(challenge, Kr, groupIDu, sID, headers={}):
    loggerauth.debug("got challenge: '%s'" % challenge)
    sID = binascii.unhexlify(sID)
    challenge = (fdecode(challenge),)
    response = fencode(Kr.decrypt(challenge))
    # XXX: RSA.decrypt won't restore leading 0's.  This causes
    #      some challenges to fail when they shouldn't -- solved for now
    #      on the server side by generating non-0 leading challenges.
    loggerauth.debug("decrypted challenge to %s" % response)
    responseID = fdecode(response)[:len(sID)]
    loggerauth.debug("  response id: %s" % fencode(responseID))
    if responseID != sID:
        # fail the op.
        # If we don't do this, we may be allowing the server to build a
        # dictionary useful for attack.  The attack is as follows: node A
        # (server) collects a bunch of un-IDed challenge/response pairs by
        # issuing challenges to node B (client).  Then node A uses those
        # responses to pose as B to some other server C.  This sounds
        # farfetched, in that such a database would need to be huge, but in
        # reality, such an attack can happen in real-time, with node A
        # simultaneously serving requests from B, relaying challenges from C to
        # B, and then responding with B's responses to C to gain resources
        # there as an imposter.  The ID string prevents this attack.

        # XXX: trust-- (must go by ip:port, since ID could be innocent)
        raise ImposterException("node %s is issuing invalid challenges --"
                " claims to have id=%s" % (fencode(sID), fencode(responseID)))
    response = fdecode(response)[len(sID):]
    loggerauth.debug("  challenge response: '%s'" % fencode(response))
    response = fencode(response)+":"+groupIDu
    loggerauth.debug("response:groupIDu=%s" % response)
    response = binascii.b2a_base64(response)
    loggerauth.debug("b64(response:groupIDu)=%s" % response)
    response = "Basic %s" % response
    headers['Authorization'] = response
    return headers 
Example #6
0
def endtests(res, nKu, node, host, port):
    """ executes after all tests """
    try:
        res = fdecode(res)
    except ValueError:
        pass
    if res != testval:
        return testerror(None, "retrieved value does not match stored value:"
                " '%s' != '%s'" % (res, testval), node)
    
    logger.info("testkFindVal PASSED")
    logger.debug("testkFindVal result: %s" % str(res))

    logger.info("all tests PASSED")
    return res
Example #7
0
def expireChallenge(challenge, expired=False):
    try:
        challenge = fdecode(challenge)
    except:
        pass
    if outstandingChallenges.has_key(challenge):
        del outstandingChallenges[challenge]
        if expired:
            # XXX: should put these in an expired challenge list so that we
            #      can send a more useful message on failure (must then do
            #      expirations on expired list -- maybe better to just make
            #      these expirations really liberal).
            loggerauth.debug("expired challenge %s" % fencode(challenge))
        else:
            loggerauth.debug("deleted challenge %s" % fencode(challenge))
Example #8
0
 def __init__(self, fname, mode):
     # XXX: need to check fname and throw if it isn't a proper BlockFile
     self._fname = fname
     self.mode = mode
     self._file = __builtin__.open(fname, mode)
     sizeString = self._file.read(8)
     self._size = struct.unpack('=Q',sizeString)[0]
     self._dataend = 8 + self._size
     self._file.seek(self._dataend)
     self._accounting = fdecode(self._file.read())
     self._accountingcrc = crc32(str(self._accounting))
     self._changed = False
     if mode[0] == 'a':
         self._file.seek(self._dataend)
     else:
         self._file.seek(8) 
Example #9
0
 def lineReceived(self, line):
     logger.debug("received line '%s'" % line)
     command = line[0:4]
     if not command in VALIDOPS:
         print "error: invalid command op ('%s')-- "\
                 " are you trying to connect to the wrong port"\
                 " (local client port is usually external port + 500)?"\
                 % command
         return None
     status = line[4]
     data = line[5:]
     if not self.auth:
         if command == "AUTH" and status == '?':
             # got challenge, send response
             logger.debug("got AUTH challenge, sending response")
             echallenge = data
             self.sendLine("AUTH:"+self.factory.answerChallenge(echallenge))
             return
         elif command == "AUTH" and status == ':':
             # response accepted, authenticated
             logger.debug("AUTH challenge accepted, success")
             self.auth = True
             self.factory.clientReady(self)
             #print "authenticated"
         else:
             if command == "AUTH" and status == "!":
                 logger.warn("authentication failed (is FLUDHOME set"
                     " correctly?)")
                 print "authentication failed (is FLUDHOME set correctly?)"
             else:
                 logger.warn("unknown message received before being"
                         " authenticated:")
                 logger.warn("  %s : %s" % (command, status))
                 print "unknown message received before being authenticated:"
                 print "  %s : %s" % (command, status)
             self.factory.setDie()
     elif command == "DIAG":
         subcommand = data[:4]
         data = data[4:]
         if subcommand == "NODE":
             logger.debug("DIAG NODE: %s" % data)
             data = fdecode(data)
             result = ""
             for i in data:
                 score = '%d' % i[4]
                 petID = "%064x" % i[2]
                 netID = "%s:%d" % (i[0], i[1])
                 if i[5] != 0:
                     now = int(time.time())
                     throttle = '(%d)' % (i[5]-now)
                     petID = petID[:(70-len(netID)-len(throttle))]+"... " \
                             +throttle
                 else:
                     petID = petID[:(70-len(netID))]+"..."
                 result += "%s %s %s\n" % (score, netID, petID)
             result += "%d known nodes\n" % len(data)
             d = self.factory.pending['NODE'].pop('')
             d.callback(result)
             return
         if subcommand == "BKTS":
             logger.debug("DIAG BKTS")
             data = fdecode(data)
             result = ""
             for i in data:
                 for bucket in i:
                     result += "Bucket %s:\n" % bucket
                     for k in i[bucket]:
                         id = "%064x" % k[2]
                         netID = "%s:%d" % (k[0], k[1])
                         result += "  %s %s...\n" \
                                 % (netID,id[:72-len(netID)])
             d = self.factory.pending['BKTS'].pop('')
             d.callback(result)
             return
         elif status == ':':
             response, data = data.split(status, 1)
             logger.debug("DIAG %s: success" % subcommand)
             d = self.factory.pending[subcommand].pop(data)
             d.callback(fdecode(response))
         elif status == "!":
             response, data = data.split(status, 1)
             logger.debug("DIAG %s: failure" % subcommand)
             d = self.factory.pending[subcommand].pop(data)
             d.errback(failure.DefaultException(response))
     elif status == ':':
         response, data = data.split(status, 1)
         logger.debug("%s: success" % command)
         d = self.factory.pending[command].pop(data)
         d.callback(fdecode(response))
     elif status == "!":
         response, data = data.split(status, 1)
         logger.debug("%s: failure" % command)
         if self.factory.pending.has_key(command):
             if data not in self.factory.pending[command]:
                 #print "data key is '%s'" % data
                 print "pending is '%s'" % self.factory.pending[command]
                 if len(self.factory.pending[command]):
                     d = self.factory.pending[command].popitem()
                     d.errback(failure.DefaultException(response))
             else:
                 d = self.factory.pending[command].pop(data)
                 d.errback(failure.DefaultException(response))
         else:
             print "failed command '%s' not in pending?" % command
             print "pending is: %s" % self.factory.pending
     if command != 'AUTH' and command != 'DIAG' and \
             not None in self.factory.pending[command].values():
         logger.debug("%s done at %s" % (command, time.ctime()))
Example #10
0
 def answerChallenge(self, echallenge):
     logger.debug("answering challenge")
     echallenge = (fdecode(echallenge),)
     challenge = self.config.Kr.decrypt(echallenge)
     return challenge
Example #11
0
 def doOp(self, command, fname):
     #print "got command '%s'" % command
     if command == "PUTF":
         logger.debug("PUTF %s", fname);
         return FileOps.StoreFile(self.factory.node, fname).deferred
     elif command == "GETI":
         logger.debug("GETI %s", fname);
         return FileOps.RetrieveFile(self.factory.node, fname).deferred
     elif command == "GETF":
         logger.debug("GETF %s", fname);
         return FileOps.RetrieveFilename(self.factory.node, fname).deferred
     elif command == "FNDN":
         logger.debug("FNDN %s" % fname);
         try: 
             intval = long(fname, 16)
         except: 
             return defer.fail("fname was not hex")
         return self.factory.node.client.kFindNode(intval)
         # The following is for testing aggregation of kFindNode on same key
         #dl = []
         #for i in [1,2,3,4,5]:
         #   d = self.factory.node.client.kFindNode(intval)
         #   dl.append(d)
         #dlist = defer.DeferredList(dl)
         #return dlist
     elif command == "FNDV":
         logger.debug("FNDV %s", fname);
         try: 
             intval = long(fname, 16)
         except: 
             return defer.fail("fname was not hex")
         return self.factory.node.client.kFindValue(intval)
     elif command == "CRED":
         passphrase, email = fdecode(fname)
         # XXX: allow an optional passphrase hint to be sent in email.
         passphrase = self.factory.node.config.Kr.decrypt(passphrase)
         logger.debug("CRED %s to %s", passphrase, email);
         Kr = self.factory.node.config.Kr.exportPrivateKey()
         Kr['g'] = self.factory.node.config.groupIDr
         fKr = fencode(Kr)
         key = AES.new(binascii.unhexlify(hashstring(passphrase)))
         fKr = '\x00'*(16-(len(fKr)%16))+fKr
         efKr = fencode(key.encrypt(fKr))
         logger.debug("efKr = %s " % efKr)
         d = smtp.sendmail('localhost', "your_flud_client@localhost", 
                 email,
                 "Subject: Your encrypted flud credentials\n\n"
                 "Hopefully, you'll never need to use this email.  Its "
                 "sole purpose is to help you recover your data after a "
                 "catastrophic and complete loss of the original computer "
                 "or hard drive.\n\n"
                 "In that unlucky event, you'll need a copy of your flud "
                 "credentials, which I've included below, sitting between "
                 "the \"---+++---\" markers.  These credentials were "
                 "encrypted with a passphrase of your choosing when you "
                 "installed the flud software.  I'll only say this "
                 "once:\n\n"
                 "YOU MUST REMEMBER THAT PASSWORD IN ORDER TO RECOVER YOUR "
                 "CREDENTIALS.  If you are unable to remember the "
                 "passphrase and your computer fails catastrophically "
                 "(losing its local copy of these credentials), you will "
                 "not be able to recover your data."
                 "\n\n"
                 "Luckily, that's all you should ever need in order to "
                 "recover all your data: your passphrase and these "
                 "credentials."
                 "\n\n"
                 "Please save this email.  You may want to print out hard "
                 "copies and store them safely, forward this email to "
                 "other email accounts, etc.  Since the credentials are "
                 "encrypted, others won't be able to steal them "
                 "without guessing your passphrase. "
                 "\n\n"
                 "---+++---\n"+efKr+"\n---+++---\n")
         return d
         # to decode this email, we search for the '---+++---' markers, make
         # sure the intervening data is all in one piece (remove any line
         # breaks \r or \n inserted by email clients) and call this 'cred',
         # reconstruct the AES key with the H(passphrase) (as above), and
         # then use the key to .decrypt(fdecode(cred)) and call this dcred,
         # then fdecode(dcred[dcred.find('d'):]) and call this ddcred, and
         # finally importPrivateKey(ddcred) and set groupIDr to ddcred['g'].
     elif command == "LIST":
         logger.debug("LIST")
         return defer.succeed(self.factory.config.master)
     elif command == "GETM":
         logger.debug("GETM")
         return FileOps.RetrieveMasterIndex(self.factory.node).deferred
     elif command == "PUTM":
         logger.debug("PUTM")
         return FileOps.UpdateMasterIndex(self.factory.node).deferred
     else:
         #print "fname is '%s'" % fname
         host = fname[:fname.find(':')]
         port = fname[fname.find(':')+1:fname.find(',')]
         fname = fname[fname.find(',')+1:]
         print "%s: %s : %s , %s" % (command, host, port, fname)
         if command == "STOR":
             logger.debug("STOR");
             return self.factory.node.client.sendStore(fname, None, 
                     host, int(port))
         elif command == "RTRV":
             logger.debug("RTRV");
             return self.factory.node.client.sendRetrieve(fname, host, 
                     int(port))
         elif command == "VRFY":
             logger.debug("VRFY");
             offset = port[port.find(':')+1:port.find('-')]
             length = port[port.find('-')+1:]
             port = port[:port.find(':')]
             print "%s: %s : %s %s - %s , %s" % (command, host, port, 
                     offset, length, fname)
             return self.factory.node.client.sendVerify(fname, int(offset), 
                     int(length), host, int(port))
         else:
             logger.debug("bad op");
             return defer.fail("bad op")
Example #12
0
            required = ('Ku_e', 'Ku_n', 'port', 'offset', 'length')
            params = requireParams(request, required)
        except Exception, inst:
            msg = inst.args[0] + " in request received by VERIFY" 
            loggervrfy.log(logging.INFO, msg)
            request.setResponseCode(http.BAD_REQUEST, "Bad Request")
            loggervrfy.debug("BAD REQUEST")
            return msg 
        else:
            host = getCanonicalIP(request.getClientIP())
            port = int(params['port'])
            loggervrfy.log(logging.INFO,
                    "received VERIFY request from %s:%s...", host, port)
            if 'meta' in request.args:
                params['metakey'] = request.args['metakey'][0]
                params['meta'] = fdecode(request.args['meta'][0])
                loggerretr.info("VERIFY contained meta field with %d chars"
                        % len(params['meta']))
                meta = (params['metakey'], params['meta'])
            else:
                meta = None

            offset = int(params['offset'])
            length = int(params['length'])
            paths = [p for p in filekey.split(os.path.sep) if p != '']
            if len(paths) > 1:
                msg = "Bad request:"\
                        " filekey contains illegal path seperator tokens."
                loggerretr.debug(msg)
                request.setResponseCode(http.BAD_REQUEST, msg)
                return msg
Example #13
0
            return msg 
        else:
            logger.info("received kFINDNODE request from %s..."
                    % params['nodeID'][:10])
            reqKu = {}
            reqKu['e'] = long(params['Ku_e'])
            reqKu['n'] = long(params['Ku_n'])
            reqKu = FludRSA.importPublicKey(reqKu)
            if reqKu.id() != params['nodeID']:
                request.setResponseCode(http.BAD_REQUEST, "Bad Identity")
                return "requesting node's ID and public key do not match"
            host = getCanonicalIP(request.getClientIP())
            #return "{'id': '%s', 'k': %s}"\
            #       % (self.config.nodeID,\
            #       self.config.routing.findNode(fdecode(params['key'])))
            kclosest = self.config.routing.findNode(fdecode(key))
            notclose = list(set(self.config.routing.knownExternalNodes()) 
                    - set(kclosest))
            if len(notclose) > 0 and len(kclosest) > 1:
                r = random.choice(notclose)
                #logger.info("**** got some notclose: %s:%d ****" % (r[0],r[1]))
                kclosest.append(r)
            #logger.info("returning kFINDNODE response: %s" % kclosest)
            updateNode(self.node.client, self.config, host, 
                    int(params['port']), reqKu, params['nodeID'])
            return "{'id': '%s', 'k': %s}" % (self.config.nodeID, kclosest)
        
class kSTORE_true(ROOT):
    # unrestricted kSTORE.  Will store any key/value pair, as in generic
    # kademlia.  This should be unregistered in FludServer (can't allow
    # generic stores).