def init(owner, users, groups): """ init will initialize a new share root as the given user principal. This includes setting up . and .. in the root directory, as well as adding the .users and .groups files that list trusted user public keys and group memberships respectively. This function will only allocate the share's root, but not map it to any particular share at the server. The new root's i is returned so that this can be done by the caller. """ if not isinstance(owner, User): raise TypeError("{} is not a User, is a {}".format(owner, type(owner))) node = Inode() node.kind = 0 node.ex = True node.ctime = time.time() node.mtime = node.ctime ihash = secfs.store.block.store(node.bytes(), None) # inodes not encrypted root_i = secfs.tables.modmap(owner, I(owner), ihash) if root_i == None: raise RuntimeError new_ihash = secfs.store.tree.add(root_i, b'.', root_i) secfs.tables.modmap(owner, root_i, new_ihash) new_ihash = secfs.store.tree.add( root_i, b'..', root_i) # TODO(eforde): why would .. be mapped to root_i? secfs.tables.modmap(owner, root_i, new_ihash) print("CREATED ROOT AT", new_ihash) init = { b".users": users, b".groups": groups, } import pickle for fn, c in init.items(): bts = pickle.dumps(c) node = Inode() node.kind = 1 node.size = len(bts) node.mtime = node.ctime node.ctime = time.time() node.blocks = [secfs.store.block.store(bts, None)] # don't encrypt init ihash = secfs.store.block.store(node.bytes(), None) # inodes not encrypted i = secfs.tables.modmap(owner, I(owner), ihash) link(owner, i, root_i, fn) return root_i
def _create(parent_i, name, create_as, create_for, isdir): """ _create allocates a new file, and links it into the directory at parent_i with the given name. The new file is owned by create_for, but is created using the credentials of create_as. This distinction is necessary as a user principal is needed for the final i when creating a file as a group. """ if not isinstance(parent_i, I): raise TypeError("{} is not an I, is a {}".format( parent_i, type(parent_i))) if not isinstance(create_as, User): raise TypeError("{} is not a User, is a {}".format( create_as, type(create_as))) if not isinstance(create_for, Principal): raise TypeError("{} is not a Principal, is a {}".format( create_for, type(create_for))) assert create_as.is_user() # only users can create assert create_as == create_for or create_for.is_group( ) # create for yourself or for a group if create_for.is_group() and create_for not in groupmap: raise PermissionError( "cannot create for unknown group {}".format(create_for)) # This check is performed by link() below, but better to fail fast if not secfs.access.can_write(create_as, parent_i): if parent_i.p.is_group(): raise PermissionError( "cannot create in group-writeable directory {0} as {1}; user is not in group" .format(parent_i, create_as)) else: raise PermissionError( "cannot create in user-writeable directory {0} as {1}".format( parent_i, create_as)) node = Inode() node.ctime = time.time() node.mtime = node.ctime node.kind = 0 if isdir else 1 node.ex = isdir # FIXME # # Here, you will need to: # # - store the newly created inode (node.bytes()) on the server # - map that block to an i owned by the user # - if a directory is being created, create entries for . and .. # - if create_for is a group, you will also have to create a group i for # that group, and point it to the user's i # - call link() to link the new i into the directory at parent_i with the # given name # # Also make sure that you *return the final i* for the new inode! return I(User(0), 0)
def _create(parent_i, name, create_as, create_for, isdir, encrypt): """ _create allocates a new file, and links it into the directory at parent_i with the given name. The new file is owned by create_for, but is created using the credentials of create_as. This distinction is necessary as a user principal is needed for the final i when creating a file as a group. """ if not isinstance(parent_i, I): raise TypeError("{} is not an I, is a {}".format( parent_i, type(parent_i))) if not isinstance(create_as, User): raise TypeError("{} is not a User, is a {}".format( create_as, type(create_as))) if not isinstance(create_for, Principal): raise TypeError("{} is not a Principal, is a {}".format( create_for, type(create_for))) assert create_as.is_user() # only users can create assert create_as == create_for or create_for.is_group( ) # create for yourself or for a group if create_for.is_group() and create_for not in groupmap: raise PermissionError( "cannot create for unknown group {}".format(create_for)) # This check is performed by link() below, but better to fail fast if not secfs.access.can_write(create_as, parent_i): if parent_i.p.is_group(): raise PermissionError( "cannot create in group-writeable directory {0} as {1}; user is not in group" .format(parent_i, create_as)) else: raise PermissionError( "cannot create in user-writeable directory {0} as {1}".format( parent_i, create_as)) # TODO(eforde): encrypt if parent directory is encrypted # encrypt = encrypt or parent_i.encrypted node = Inode() node.encrypted = 1 if encrypt else 0 node.ctime = time.time() node.mtime = node.ctime node.kind = 0 if isdir else 1 node.ex = isdir # store the newly created inode on the server new_hash = secfs.store.block.store(node.bytes(), None) # inodes not encrypted # map the block to an i owned by create_for, created with credentials of create_as new_i = secfs.tables.modmap(create_as, I(create_for), new_hash) if isdir: # create . and .. if this is a directory table_key = secfs.tables.get_itable_key(create_for, create_as) new_ihash = secfs.store.tree.add(new_i, b'.', new_i, table_key) secfs.tables.modmap(create_as, new_i, new_ihash) new_ihash = secfs.store.tree.add(new_i, b'..', parent_i, table_key) secfs.tables.modmap(create_as, new_i, new_ihash) # link the new i into the directoy at parent_i with the given name link(create_as, new_i, parent_i, name) return new_i
def _create(parent_i, name, create_as, create_for, isdir, encrypt): """ _create allocates a new file, and links it into the directory at parent_i with the given name. The new file is owned by create_for, but is created using the credentials of create_as. This distinction is necessary as a user principal is needed for the final i when creating a file as a group. """ if not isinstance(parent_i, I): raise TypeError("{} is not an I, is a {}".format( parent_i, type(parent_i))) if not isinstance(create_as, User): raise TypeError("{} is not a User, is a {}".format( create_as, type(create_as))) if not isinstance(create_for, Principal): raise TypeError("{} is not a Principal, is a {}".format( create_for, type(create_for))) assert create_as.is_user() # only users can create assert create_as == create_for or create_for.is_group( ) # create for yourself or for a group if create_for.is_group() and create_for not in groupmap: raise PermissionError( "cannot create for unknown group {}".format(create_for)) # This check is performed by link() below, but better to fail fast if not secfs.access.can_write(create_as, parent_i): if parent_i.p.is_group(): raise PermissionError( "cannot create in group-writeable directory {0} as {1}; user is not in group" .format(parent_i, create_as)) else: raise PermissionError( "cannot create in user-writeable directory {0} as {1}".format( parent_i, create_as)) node = Inode() node.ctime = time.time() node.mtime = node.ctime node.kind = 0 if isdir else 1 node.ex = isdir # Encrypt if needed sym_key = None if encrypt: symkey = Fernet.generate_key() node.encrypt(create_for, symkey) # Here, you will need to: # # - [DONE] store the newly created inode (node.bytes()) on the server # - [DONE] map that block to an i owned by the user # - [DONE] if a directory is being created, create entries for . and .. # - [DONE] if create_for is a group, you will # also have to create a group i for that group, and point it to the user's i # - [DONE] call link() to link the new i into the directory at parent_i with the # given name # # Also make sure that you *return the final i* for the new inode! new_ihash = secfs.store.block.store(node.bytes()) new_i = secfs.tables.modmap(create_as, I(create_for), new_ihash) if isdir: # link calls tree.add and modmap within link(create_as, new_i, new_i, b'.') link(create_as, parent_i, new_i, b'..') # Finally link this directory to the parent link(create_as, new_i, parent_i, name) return new_i