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
13 #include <minix/callnr.h>
17 #include <minix/vfsif.h>
21 FORWARD
_PROTOTYPE( in_group
, (gid_t grp
) );
23 /*===========================================================================*
25 *===========================================================================*/
28 /* Perform the chmod(name, mode) and fchmod(fd, mode) system calls. */
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
);
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
)
54 /* If error, return inode. */
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
;
72 /*===========================================================================*
74 *===========================================================================*/
77 /* Perform the chmod(name, mode) and fchmod(fd, mode) system calls. */
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
);
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
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
;
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
,
119 vp
->v_mode
= new_mode
;
128 /*===========================================================================*
130 *===========================================================================*/
131 PUBLIC
int do_umask()
133 /* Perform the umask(co_mode) system call. */
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 /*===========================================================================*
144 *===========================================================================*/
145 PUBLIC
int do_access()
147 /* Perform the access(name, mode) system call. */
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
)
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
);
165 /*===========================================================================*
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
;
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. */
186 uid
= (call_nr
== ACCESS
? fp
->fp_realuid
: fp
->fp_effuid
);
187 gid
= (call_nr
== ACCESS
? fp
->fp_realgid
: fp
->fp_effgid
);
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
;
198 perm_bits
= R_BIT
| W_BIT
;
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. */
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
215 if (access_desired
& W_BIT
)
222 /*===========================================================================*
224 *===========================================================================*/
225 PRIVATE
int in_group(gid_t grp
)
229 for (i
= 0; i
< fp
->fp_ngroups
; i
++)
230 if (fp
->fp_sgroups
[i
] == grp
)
237 /*===========================================================================*
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
;
249 return(mp
->m_flags
? EROFS
: OK
);