diff options
Diffstat (limited to 'libtreefs/node-hooks.c')
-rw-r--r-- | libtreefs/node-hooks.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/libtreefs/node-hooks.c b/libtreefs/node-hooks.c new file mode 100644 index 00000000..faffcd6a --- /dev/null +++ b/libtreefs/node-hooks.c @@ -0,0 +1,176 @@ +/* Default hooks for nodes + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "treefs.h" + +/* ---------------------------------------------------------------- */ +/* These default hooks depend on stat information being correct. */ + +/* Returns the type of NODE, as an S_IFMT value (e.g., S_IFDIR). The + default routine just looks at NODE's stat mode. */ +int +_treefs_node_type (struct treefs_node *node) +{ + return node->stat.st_mode & S_IFMT; +} + +/* Return TRUE if NODE is `unlinked' -- that is, can be deleted when all + (in-memory) references go away. */ +int +_treefs_node_unlinked (struct treefs_node *node) +{ + return node->stat.st_nlinks == 0; +} + +/* Changes the link count of NODE by CHANGE; if any error is returned, the + operation trying to change the link count will fail, so filesystems that + don't support real links can restrict it to 1 or 0. This is mostly used + by the in-core directory code when it makes a link. The default hook uses + the link field of NODE's stat entry. */ +error_t +_treefs_node_mod_link_count (struct treefs_node *node, int change) +{ + node->stat.st_nlinks += change; +} + + +/* ---------------------------------------------------------------- */ +/* These default hooks depend on stat information being correct. */ + +/* Returns the user and group that a newly started translator should be + authenticated as. The default just returns the owner/group of NODE. */ +error_t +_treefs_node_get_trans_auth (struct treefs_node *node, uid_t *uid, gid_t *gid) +{ + *uid = node->stat.st_uid; + *gid = node->stat.st_gid; + return 0; +} + +/* Check to see is the user identified by AUTH is permitted to do + operation OP on node NP. Op is one of S_IREAD, S_IWRITE, or S_IEXEC. + Return 0 if the operation is permitted and EACCES if not. */ +error_t +_treefs_node_access (struct treefs_node *node, + int op, struct treefs_auth *auth) +{ + int gotit; + if (diskfs_auth_has_uid (auth, 0)) + gotit = 1; + else if (auth->nuids == 0 && (node->stat.st_mode & S_IUSEUNK)) + gotit = node->stat.st_mode & (op << S_IUNKSHIFT); + else if (!treefs_node_owned (node, auth)) + gotit = node->stat.st_mode & op; + else if (treefs_auth_in_group (auth, node->stat.st_gid)) + gotit = node->stat.st_mode & (op >> 3); + else + gotit = node->stat.st_mode & (op >> 6); + return gotit ? 0 : EACCES; +} + +/* Check to see if the user identified by AUTH is permitted to do owner-only + operations on node NP; if so, return 0; if not, return EPERM. */ +error_t +_treefs_node_owned (struct treefs_node *node, struct treefs_auth *auth) +{ + /* Permitted if the user is the owner, superuser, or if the user + is in the group of the file and has the group ID as their user + ID. (This last is colloquially known as `group leader'.) */ + if (treefs_auth_has_uid (auth, node->stat.st_uid) + || treefs_auth_has_uid (auth, 0) + || (treefs_auth_in_group (auth, node->stat.st_gid) + && treefs_auth_has_uid (auth, node->stat.st_gid))) + return 0; + else + return EPERM; +} + +/* ---------------------------------------------------------------- */ + +error_t +_treefs_node_init_stat (struct treefs_node *node, struct treefs_node *dir, + mode_t mode, struct treefs_auth *auth) +{ + if (auth->nuids) + node->stat.st_uid = auth->uids[0]; + else + { + mode &= ~S_ISUID; + if (dir) + node->stat.st_uid = dir->stat.st_uid; + else + node->stat.st_uid = -1; /* XXX */ + } + + if (dir && diskfs_ingroup (dir->stat.st_gid, auth)) + node->stat.st_gid = dir->stat.st_gid; + else if (auth->ngids) + node->stat.st_gid = auth->gids[0]; + else + { + mode &= ~S_ISGID; + if (dir) + node->stat.st_gid = dir->stat.st_gid; + else + node->stat.st_gid = -1; /* XXX */ + } + + node->stat.st_rdev = 0; + node->stat.st_nlink = 0; + node->stat.st_mode = mode; + + node->stat.st_blocks = 0; + node->stat.st_size = 0; + node->stat.st_flags = 0; + + return 0; +} + +/* ---------------------------------------------------------------- */ + +/* Called when the new peropen structure PO is made for NODE, with the + authorization in AUTH, opened with the flags FLAGS. If an error is + returned, the open will fail with that error. The default hook does + explicit authorization checks against AUTH using treefs_node_access, and + otherwise does nothing. */ +error_t +_treefs_init_peropen (struct treefs_node *node, struct treefs_peropen *po, + int flags, struct treefs_auth *auth) +{ + error_t err; + + if (flags & O_READ) + err = treefs_node_access (node, S_IREAD, auth); + if (!err && (flags & O_EXEC)) + err = treefs_node_access (node, S_IEXEC, auth); + if (!err && (flags & O_WRITE)) + { + if (type == S_IFDIR) + err = EISDIR; + else if (auth->po->node->fsys->readonly) + err = EROFS; + else + err = treefs_node_access (node, S_IWRITE, auth); + } + + return err; +} |