def logProtectedCall(result, path, args, user, allowed=True): """This should be called when a protected call was attempted, successful or not. It logs the attempt and its results in the audit_trail database. This audit trail can be used for several things- listing recently updated metadata (perhaps for a 'whats new?' page) or detecting and recovering from malicious use of keys. """ # Store the first argument separately so we can relatively efficiently search for it if args: main_param = str(args[0]) else: main_param = None # Get the user's UID. If it hasn't even been looked up successfully, # this is just a failed operation on a nonexistent user and it's not worth logging. uid = user.getCachedUid() if uid is None: return Database.pool.runOperation( "INSERT INTO audit_trail (timestamp, uid, action_domain, action_name," " main_param, params, allowed, results)" " VALUES(%d, %d, 'protected_call', %s, %s, '%s', %d, '%s')" % ( time.time(), uid, Database.quote(".".join(path), 'text'), Database.quote(main_param, 'text'), Database.quoteBlob(cPickle.dumps(args)), allowed, Database.quoteBlob(cPickle.dumps(result)))) return result
def _grant(self, cursor, *capabilities): uid = self._getUid(cursor) for capability in capabilities: rep = repr(capability) print rep cursor.execute("INSERT IGNORE INTO capabilities (uid, cap_md5, cap_repr)" " VALUES(%d, %s, %s)" % ( uid, Database.quote(hashlib.md5(rep).hexdigest(), 'char'), Database.quote(rep, 'text')))
def _createUser(self, cursor): """Create a new user, optionally setting the given parameters. Returns the new user ID. """ log.msg("Creating new user %r" % self._full_name) self.newUser = True cursor.execute("INSERT INTO users (secret_key, creation_time, full_name, email, login_name) " "VALUES (%s, %d, %s, %s, %s)" % ( Database.quote(createRandomKey(), 'varchar'), time.time(), Database.quote(self._full_name, 'text'), Database.quote(self._email, 'text'), Database.quote(self._login_name, 'varchar'))) cursor.execute("SELECT LAST_INSERT_ID()") return int(cursor.fetchone()[0])
def _getUidFromEmail(self, cursor, name): """Find a user by email address""" cursor.execute("SELECT uid FROM users WHERE email = %s" % Database.quote(name, 'text')) row = cursor.fetchone() if row: return int(row[0]) else: raise NoSuchUser("No such email address: %r" % name)
def _getUidFromLoginName(self, cursor, name): """Find a user by login name""" cursor.execute("SELECT uid FROM users WHERE login_name = %s" % Database.quote(name, 'text')) row = cursor.fetchone() if row: return int(row[0]) else: raise NoSuchUser("No such login name: %r" % name)
def _getUidFromKey(self, cursor, key): """Find a user by their key""" cursor.execute("SELECT uid FROM users WHERE secret_key = %s" % Database.quote(key.strip(), 'varchar')) row = cursor.fetchone() if row: return int(row[0]) else: raise NoSuchUser("No user found matching the given key")
def _getUidFromFullName(self, cursor, name): """Find a user by full name""" if name is None: cursor.execute("SELECT uid FROM users WHERE full_name is NULL") else: cursor.execute("SELECT uid FROM users WHERE full_name = %s" % Database.quote(name, 'text')) row = cursor.fetchone() if row: return int(row[0]) else: raise NoSuchUser("No such name: %r" % name)
def _createTestQuery(self, uid, capabilities): """Create an SQL query that returns something nonzero if a uid matches any of a list of capabilities. If the capabilities list is empty, this creates a query that always has a nonzero result. """ if capabilities: return "SELECT 1 FROM capabilities WHERE uid = %d AND (%s) LIMIT 1" % ( uid, " OR ".join(["cap_md5 = " + Database.quote(hashlib.md5(repr(c)).hexdigest(), 'char') for c in capabilities]), ) else: return "SELECT 1"
def dbStore(self, ruleset): """Store a ruleset persistently in our SQL database""" # Delete the old ruleset, if there was one result = defer.Deferred() d = Database.pool.runOperation("DELETE FROM rulesets WHERE uri = %s" % Database.quote(ruleset.uri, 'text')) # If we need to insert a new ruleset, do that after the delete finishes if ruleset.isEmpty(): d.addCallback(result.callback) else: d.addCallback(self._insertRuleset, result, ruleset) d.addErrback(result.errback) return result
def _insertRuleset(self, none, result, ruleset): """Callback used by store() to insert a new or modified ruleset into the SQL database""" d = Database.pool.runOperation("INSERT INTO rulesets (uri, xml) values(%s, %s)" % ( Database.quote(ruleset.uri, 'text'), Database.quote(ruleset.get_source(), 'text'))) d.addCallback(result.callback) d.addErrback(result.errback)
allowed BOOL NOT NULL, results LONGBLOB, FOREIGN KEY (uid) REFERENCES users(uid) ON DELETE CASCADE, INDEX (id), INDEX (uid) ) TYPE=INNODB """) # Populate the user table, saving the resulting UIDs key_uids = {} for key in key_owner.iterkeys(): cursor.execute("INSERT INTO users (secret_key, full_name, email, creation_time) " "VALUES (%s, %s, %s, %d)" % ( Database.quote(key, 'varchar'), Database.quote(key_owner[key], 'varchar'), Database.quote(key_ownerMail[key], 'varchar'), time.time())) cursor.execute("SELECT LAST_INSERT_ID()") key_uids[key] = cursor.fetchone()[0] # Populate the capabilities table for key in key_owner.iterkeys(): for capability in key_capabilities[key]: cursor.execute("INSERT INTO capabilities (uid, cap_md5, cap_repr) VALUES(%s, %s, %s)" % ( key_uids[key], Database.quote(md5.new(capability).hexdigest(), 'char'), Database.quote(capability, 'text'))) # Seems this was a success, bump the db version