panic() cleanup.
[minix.git] / servers / vfs / protect.c
blobb72828c4f174974155ab19586539a27960195cef
1 /* This file deals with protection in the file system. It contains the code
2 * for four system calls that relate to protection.
4 * The entry points into this file are
5 * do_chmod: perform the CHMOD and FCHMOD system calls
6 * do_chown: perform the CHOWN and FCHOWN system calls
7 * do_umask: perform the UMASK system call
8 * do_access: perform the ACCESS system call
9 */
11 #include "fs.h"
12 #include <unistd.h>
13 #include <minix/callnr.h>
14 #include "file.h"
15 #include "fproc.h"
16 #include "param.h"
17 #include <minix/vfsif.h>
18 #include "vnode.h"
19 #include "vmnt.h"
21 FORWARD _PROTOTYPE( in_group, (gid_t grp) );
23 /*===========================================================================*
24 * do_chmod *
25 *===========================================================================*/
26 PUBLIC int do_chmod()
28 /* Perform the chmod(name, mode) and fchmod(fd, mode) system calls. */
30 struct filp *flp;
31 struct vnode *vp;
32 int r;
33 mode_t new_mode;
35 if (call_nr == CHMOD) {
36 /* Temporarily open the file */
37 if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
38 if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) return(err_code);
39 } else { /* call_nr == FCHMOD */
40 /* File is already opened; get a pointer to vnode from filp. */
41 if (!(flp = get_filp(m_in.fd))) return(err_code);
42 vp = flp->filp_vno;
43 dup_vnode(vp);
46 /* Only the owner or the super_user may change the mode of a file.
47 * No one may change the mode of a file on a read-only file system.
49 if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID)
50 r = EPERM;
51 else
52 r = read_only(vp);
54 /* If error, return inode. */
55 if (r != OK) {
56 put_vnode(vp);
57 return(r);
60 /* Now make the change. Clear setgid bit if file is not in caller's grp */
61 if (fp->fp_effuid != SU_UID && vp->v_gid != fp->fp_effgid)
62 m_in.mode &= ~I_SET_GID_BIT;
64 if ((r = req_chmod(vp->v_fs_e, vp->v_inode_nr, m_in.mode, &new_mode)) == OK)
65 vp->v_mode = new_mode;
67 put_vnode(vp);
68 return(OK);
72 /*===========================================================================*
73 * do_chown *
74 *===========================================================================*/
75 PUBLIC int do_chown()
77 /* Perform the chmod(name, mode) and fchmod(fd, mode) system calls. */
78 int inode_nr;
79 int fs_e;
80 struct filp *flp;
81 struct vnode *vp;
82 int r;
83 uid_t uid;
84 gid_t gid;
85 mode_t new_mode;
87 if (call_nr == CHOWN) {
88 /* Temporarily open the file. */
89 if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
90 if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) return(err_code);
91 } else { /* call_nr == FCHOWN */
92 /* File is already opened; get a pointer to the vnode from filp. */
93 if (!(flp = get_filp(m_in.fd))) return(err_code);
94 vp = flp->filp_vno;
95 dup_vnode(vp);
98 r = read_only(vp);
99 if (r == OK) {
100 /* FS is R/W. Whether call is allowed depends on ownership, etc. */
101 /* The super user can do anything, so check permissions only if we're
102 a regular user. */
103 if (fp->fp_effuid != SU_UID) {
104 /* Regular users can only change groups of their own files. */
105 if (vp->v_uid != fp->fp_effuid) r = EPERM;
106 if (vp->v_uid != m_in.owner) r = EPERM; /* no giving away */
107 if (fp->fp_effgid != m_in.group) r = EPERM;
111 if (r == OK) {
112 /* Do not change uid/gid if new uid/gid is -1. */
113 uid = (m_in.owner == (uid_t)-1 ? vp->v_uid : m_in.owner);
114 gid = (m_in.group == (gid_t)-1 ? vp->v_gid : m_in.group);
115 if ((r = req_chown(vp->v_fs_e, vp->v_inode_nr, uid, gid,
116 &new_mode)) == OK) {
117 vp->v_uid = uid;
118 vp->v_gid = gid;
119 vp->v_mode = new_mode;
123 put_vnode(vp);
124 return(r);
128 /*===========================================================================*
129 * do_umask *
130 *===========================================================================*/
131 PUBLIC int do_umask()
133 /* Perform the umask(co_mode) system call. */
134 register mode_t r;
136 r = ~fp->fp_umask; /* set 'r' to complement of old mask */
137 fp->fp_umask = ~(m_in.co_mode & RWX_MODES);
138 return(r); /* return complement of old mask */
142 /*===========================================================================*
143 * do_access *
144 *===========================================================================*/
145 PUBLIC int do_access()
147 /* Perform the access(name, mode) system call. */
148 int r;
149 struct vnode *vp;
151 /* First check to see if the mode is correct. */
152 if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK)
153 return(EINVAL);
155 /* Temporarily open the file. */
156 if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
157 if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) return(err_code);
159 r = forbidden(vp, m_in.mode);
160 put_vnode(vp);
161 return(r);
165 /*===========================================================================*
166 * forbidden *
167 *===========================================================================*/
168 PUBLIC int forbidden(struct vnode *vp, mode_t access_desired)
170 /* Given a pointer to an vnode, 'vp', and the access desired, determine
171 * if the access is allowed, and if not why not. The routine looks up the
172 * caller's uid in the 'fproc' table. If access is allowed, OK is returned
173 * if it is forbidden, EACCES is returned.
176 register struct super_block *sp;
177 register mode_t bits, perm_bits;
178 uid_t uid;
179 gid_t gid;
180 int r, shift, type;
182 if (vp->v_uid == (uid_t) -1 || vp->v_gid == (gid_t) -1) return(EACCES);
184 /* Isolate the relevant rwx bits from the mode. */
185 bits = vp->v_mode;
186 uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
187 gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
189 if (uid == SU_UID) {
190 /* Grant read and write permission. Grant search permission for
191 * directories. Grant execute permission (for non-directories) if
192 * and only if one of the 'X' bits is set.
194 if ( (bits & I_TYPE) == I_DIRECTORY ||
195 bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
196 perm_bits = R_BIT | W_BIT | X_BIT;
197 else
198 perm_bits = R_BIT | W_BIT;
199 } else {
200 if (uid == vp->v_uid) shift = 6; /* owner */
201 else if (gid == vp->v_gid) shift = 3; /* group */
202 else if (in_group(vp->v_gid) == OK) shift = 3; /* suppl. groups */
203 else shift = 0; /* other */
204 perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
207 /* If access desired is not a subset of what is allowed, it is refused. */
208 r = OK;
209 if ((perm_bits | access_desired) != perm_bits) r = EACCES;
211 /* Check to see if someone is trying to write on a file system that is
212 * mounted read-only.
214 if (r == OK)
215 if (access_desired & W_BIT)
216 r = read_only(vp);
218 return(r);
222 /*===========================================================================*
223 * in_group *
224 *===========================================================================*/
225 PRIVATE int in_group(gid_t grp)
227 int i;
229 for (i = 0; i < fp->fp_ngroups; i++)
230 if (fp->fp_sgroups[i] == grp)
231 return(OK);
233 return(EINVAL);
237 /*===========================================================================*
238 * read_only *
239 *===========================================================================*/
240 PUBLIC int read_only(vp)
241 struct vnode *vp; /* ptr to inode whose file sys is to be cked */
243 /* Check to see if the file system on which the inode 'ip' resides is mounted
244 * read only. If so, return EROFS, else return OK.
246 register struct vmnt *mp;
248 mp = vp->v_vmnt;
249 return(mp->m_flags ? EROFS : OK);