summaryrefslogtreecommitdiff
path: root/libtreefs/node-hooks.c
blob: faffcd6a9dc2727b515f4f531d2b9256a6900c71 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
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;
}