def authenticate(request, reqKu, host, port, client, config, callable, *callargs): # 1- make sure that reqKu hashes to reqID # 2- send a challenge/groupchallenge to reqID (encrypt with reqKu) challengeResponse = request.getUser() groupResponse = request.getPassword() if not challengeResponse or not groupResponse: loggerauth.info("returning challenge for request from %s:%d" \ % (host, port)) return sendChallenge(request, reqKu, config.nodeID) else: if getChallenge(challengeResponse): expireChallenge(challengeResponse) if groupResponse == hashstring( str(reqKu.exportPublicKey()) +str(config.groupIDr)): updateNode(client, config, host, port, reqKu, reqKu.id()) return callable(*callargs) else: err = "Group Challenge Failed" loggerauth.info(err) loggerauth.debug("Group Challenge received was %s" \ % groupResponse) # XXX: update trust, routing request.setResponseCode(http.FORBIDDEN, err); return err else: err = "Challenge Failed" loggerauth.info(err) loggerauth.debug("Challenge received was %s" % challengeResponse) # XXX: update trust, routing request.setResponseCode(http.FORBIDDEN, err); return err
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")
def _sendVerify(self, request, filekey, offset, length, reqKu, nodeID, meta): fname = os.path.join(self.config.storedir,filekey) loggervrfy.debug("request for %s" % fname) if os.path.exists(fname): loggervrfy.debug("looking in regular blockfile for %s" % fname) if meta: f = BlockFile.open(fname, 'rb+') else: f = BlockFile.open(fname, 'rb') else: # check for tarball for originator loggervrfy.debug("checking tarball for %s" % fname) tarballs = [] tarballbase = os.path.join(self.config.storedir, reqKu.id())+".tar" if os.path.exists(tarballbase+".gz"): tarballs.append((tarballbase+".gz", 'r:gz')) if os.path.exists(tarballbase): tarballs.append((tarballbase, 'r')) loggervrfy.debug("tarballs is %s" % tarballs) for tarball, openmode in tarballs: loggervrfy.debug("looking in tarball %s..." % tarball) tar = tarfile.open(tarball, openmode) try: tarf = tar.extractfile(filekey) tari = tar.getmember(filekey) # XXX: update timestamp on tarf in tarball fsize = tari.size if offset > fsize or (offset+length) > fsize: # XXX: should limit length loggervrfy.debug("VERIFY response failed (from %s):" " bad offset/length" % tarball) msg = "Bad request: bad offset/length in VERIFY" request.setResponseCode(http.BAD_REQUEST, msg) return msg # XXX: could avoid seek/read if length == 0 tarf.seek(offset) # XXX: bad blocking read data = tarf.read(length) tarf.close() if meta: mfname = "%s.%s.meta" % (filekey, meta[0]) loggervrfy.debug("looking for %s" % mfname) if mfname in tar.getnames(): # make sure that the data is the same, if not, # remove it and re-add it tarmf = tar.extractfile(mfname) # XXX: bad blocking read stored_meta = tarmf.read() tarmf.close() if meta[1] != stored_meta: loggervrfy.debug("updating tarball" " metadata for %s.%s" % (filekey, meta[0])) tar.close() TarfileUtils.delete(tarball, mfname) if openmode == 'r:gz': tarball = TarfileUtils.gunzipTarball( tarball) tar = tarfile.open(tarball, 'a') metaio = StringIO(meta[1]) tinfo = tarfile.TarInfo(mfname) tinfo.size = len(meta[1]) tar.addfile(tinfo, metaio) tar.close() if openmode == 'r:gz': tarball = TarfileUtils.gzipTarball( tarball) else: loggervrfy.debug("no need to update tarball" " metadata for %s.%s" % (filekey, meta[0])) else: # add it loggervrfy.debug("adding tarball metadata" " for %s.%s" % (filekey, meta[0])) tar.close() if openmode == 'r:gz': tarball = TarfileUtils.gunzipTarball(tarball) tar = tarfile.open(tarball, 'a') metaio = StringIO(meta[1]) tinfo = tarfile.TarInfo(mfname) tinfo.size = len(meta[1]) tar.addfile(tinfo, metaio) tar.close() if openmode == 'r:gz': tarball = TarfileUtils.gzipTarball( tarball) tar.close() hash = hashstring(data) loggervrfy.info("successful VERIFY (from %s)" % tarball) return hash except: tar.close() loggervrfy.debug("requested file %s doesn't exist" % fname) msg = "Not found: not storing %s" % filekey request.setResponseCode(http.NOT_FOUND, msg) return msg # make sure request is reasonable fsize = os.stat(fname)[stat.ST_SIZE] if offset > fsize or (offset+length) > fsize: # XXX: should limit length loggervrfy.debug("VERIFY response failed (bad offset/length)") msg = "Bad request: bad offset/length in VERIFY" request.setResponseCode(http.BAD_REQUEST, msg) return msg else: # XXX: blocking # XXX: could avoid seek/read if length == 0 (noop for meta update) f.seek(offset) data = f.read(length) if meta: loggervrfy.debug("adding metadata for %s.%s" % (fname, meta[0])) f.addNode(int(nodeID, 16) , {meta[0]: meta[1]}) # XXX: blocking f.close() hash = hashstring(data) loggervrfy.debug("returning VERIFY") return hash